SEC401 - Vulnerability Management and Response
Lab 3.3 - Web App Exploitation
Solo, Lab
Focus: Web Application Security
Level: SEC401
Date: Apr 2026
Artifacts: Sanitized browser screenshots of the Alpha Inc. Merchandise catalog, injection payloads, DB enumeration, and WAF block response
TL;DR
- •Exploited a classic LIKE-based SQL injection in a PHP storefront
- •Used stacked queries to dump database and table names via SHOW statements
- •Deployed a WAF and verified it blocked the same payload (HTTP 418)
Skills demonstrated
Note: Course-provided PCAPs and lab instructions are not shared. Only my own captures and sanitized notes are published.
Why this matters
SQL injection is still in the OWASP Top 10 in 2026, and LIKE-clause injection is the version most devs miss because parameterized queries alone don't help if the app concatenates the search term into the wildcard wrapper. This lab shows the full loop: discover, exploit, defend, re-verify.
Context
This lab exercises manual SQL injection against a deliberately vulnerable PHP storefront (store.alphainc.ca:8080) backed by MySQL, then deploys a WAF and re-tests to confirm the control works.
Tools used
Steps taken
1Lab environment startup
Started the lab stack. Initial errors from stale containers, then three services came up: lab-33-php-nginx, lab-33-database, and lab-33-php-fpm. That's a classic PHP/MySQL storefront topology.
$ cd /sec401/labs/3.3/ && ./start_3.3.sh2Inspect the target app
Loaded store.alphainc.ca:8080/Catalog.php. The page exposes a category picker (attire, energy, exercise, lighting, toys, training) and a free-text search bar. The search bar is the obvious attack surface.
3Leaking the query via error
Submitted an empty search. The page printed both Array () (an empty result set) and a full PHP exception with the rendered SQL: SELECT * FROM Merchandise WHERE name LIKE '%'%'. That single line reveals: it's a LIKE query, the input is wrapped in single quotes, and stack traces are leaking to users — three serious issues before any payload.
4Confirm injection with a single quote
Submitted ' as the search term to confirm the injection context.
5Baseline: a legitimate search result
Ran a normal search to confirm the app returns product records with fields: Product Number, Item, Description, Price, Picture. The target table is clearly Merchandise.
6Probe the LIKE boundary with ';--
Submitted ';-- to close the string and try to comment out the trailing %'. The error message confirmed the resulting query: SELECT * FROM Merchandise WHERE name LIKE '%':--%', meaning MySQL didn't treat -- as a comment because it wasn't followed by whitespace.
7Observed error response
The server echoed the unsafe query directly back in the stack trace — a defender's nightmare because it tells the attacker exactly how to refine the payload.
8Fix the payload: '; -- with trailing space
MySQL's -- comment syntax requires a trailing space. Retried with '; -- (single quote, semicolon, dash-dash, space).
9Full table dump via broken WHERE clause
The payload produced SELECT * FROM Merchandise WHERE name LIKE '%'; -- %'. The first statement returned everything (LIKE '%' matches all rows), the rest got commented out. Result: all 17 products returned, confirming full data exfiltration from the table.
10Stacked query: enumerate databases
Graduated from data theft to server reconnaissance. Payload: qq'; show databases; -- . The mysqli driver in this app supports multiple statements, so the second statement executed.
11Database enumeration success
The page printed Array ( [0] => Database [1] => information_schema [2] => OnlineShop ). Confirmed the app's database is OnlineShop and stacked queries are fully allowed. From here an attacker can drop tables, write files, or escalate — the worst-case SQLi scenario.
12Deploy the WAF
Ran the lab's WAF enable script to put a filtering proxy in front of the app.
$ scripts/enable_waf.sh13Re-test the same payload
Replayed the stacked-query payload: qq'; show tables; -- . Same request, same target.
14WAF blocks the request (HTTP 418)
The WAF returned HTTP 418 ('I'm a teapot', a common non-standard block response). Identical payload, defeated. The app is still vulnerable at the code level, but the WAF gives the team time to fix it without leaving the front door open.
Key findings
Outcome / Lessons learned
Demonstrated the complete SQL injection lifecycle against a realistic PHP app: discovery from an error message, payload refinement for LIKE context, data exfiltration, information_schema enumeration via stacked queries, then defense validation with a WAF returning HTTP 418 on the same payload.
Fix the root cause: parameterize the LIKE query with bound parameters and pre-escape the user input's % and _ wildcards. Disable multi-statement on the mysqli connection. Turn off verbose error rendering in production (display_errors=Off, log to a file only). Keep the WAF as defense in depth, not the only control.
Security controls relevant
- Parameterized queries / prepared statements
- LIKE wildcard escaping (%, _)
- Disabling multi_query / stacked statements at the driver level
- Suppressing verbose error output in production
- WAF rules for SQLi (OWASP CRS)
- Least-privilege DB accounts (no SHOW DATABASES for app user)
What I took away from this
LIKE-clause injection is underestimated because most devs think 'I'm using prepared statements, I'm safe.' But a prepared statement that binds user input as the LIKE pattern without escaping % and _ still lets an attacker return every row. The bug here isn't really string concatenation, it's treating user input as a complete pattern instead of a literal.
The error page is worth as much as the injection itself. The stack trace echoed the exact generated SQL, which turned a five-minute exploit into a thirty-second one. In a real engagement I'd log 'SQL error: contact support' to the user and the full trace to a server-only log. Verbose errors in prod are a vulnerability amplifier.
The WAF worked, and that matters, but the framing is important. The app code is still exploitable. If the WAF ruleset changes, if the attacker finds an encoding the rules don't cover, or if someone routes around the WAF (internal VPC access, misconfigured origin), the exposure comes back. WAFs are brake pads, not brake lines — they buy you time, they're not the fix.