Blind Injection Behind the WAF on the Order Portal
Vantage Retail's customer portal is an ASP.NET application behind a WAF that returns 403 for UNION, for plain-text information_schema, and for common SQL keywords. The 'sort' query parameter is concatenated into an ORDER BY clause. A boolean payload changes the response length by 12 bytes; a time-based payload using inline comments returns in 5.2 seconds against a 0.2-second baseline. The application connects to MySQL 8.0 as shop_app, which holds only SELECT, INSERT, and UPDATE on the shop schema. The orders table holds 300,000 rows including names, addresses, and the last four digits of payment cards; full card numbers are tokenized in a separate PCI segment. An /admin path exists but resolves only on an internal host. Engagement rules cap extraction at the minimum needed to prove impact and require you to stop and notify on encountering regulated data.
1. How do you confirm and then exploit the injection given the WAF and the extraction cap?
Read the worked answer
Confirm with the cheapest reliable signal. Use the boolean 12-byte delta against a query whose row count you can predict, so the result is unambiguous. Confirm the time-based channel with a single call, not a loop - it exists to prove the same thing, not to extract data.
Encode around the WAF, don't fight it. The WAF matches keyword strings; the database accepts many equivalents. Hex literals and CHAR() for strings, versioned comments such as /!50000SELECT/ to break keyword matching, case and whitespace variation, and alternate comment styles. Test which encoding the backend actually honours before building on it - a payload that the parser rejects proves nothing about the WAF.
Prefer boolean over time-based for volume. Time-based extraction is slow and generates hundreds of requests, which is precisely the pattern both the WAF and the client's SOC are watching for. It is also the noisiest possible way to exceed the extraction cap.
Do not run default tooling. sqlmap with stock settings will trip the WAF and look like a real attack. If you use it at all, run single-threaded, with a delay, and a custom tamper script matching the encodings you have already validated by hand.
Extract metadata, not data. Enumerate schema names, table names, column names, and the current user's grants, and use COUNT(*) to size the orders table. That satisfies 'prove impact' without moving a single customer row - which is both the contractual requirement and the professionally correct choice.
2. Given shop_app's privileges, what is the realistic impact and what escalation routes do you evaluate?
Read the worked answer
What is not available: no file read or write without the FILE privilege, so no UDF injection and no LOAD_FILE of the config; MySQL's client APIs generally do not execute stacked statements, so no second query. The server is not one query away from operating-system compromise.
What is available, and it is enough: read and modify the shop schema - 300,000 order records with names and addresses, plus the ability to alter orders and prices. That is a confidentiality and integrity breach of exactly the data the PCI programme cares about, even though the full card numbers sit elsewhere.
Escalation routes, ordered by noise and value:
- Grants and other schemas. Check for tables holding API tokens, session data, or application credentials that shop_app can read but shouldn't.
- Application features that touch the filesystem. Invoice PDF generation, CSV import, or template rendering can turn an injection into a local file read, and the connection string in the config often belongs to a more privileged account.
- SSRF toward the internal /admin host. This is the highest-value pivot, because network position and the WAF are the only things protecting that panel. An injection-driven request from the application server may not even cross the WAF.
- Credential reuse from anything extracted, against the database host's OS or the admin panel.
Be precise in the report about PCI language: last-four digits are cardholder-adjacent data under PCI DSS, but claiming full cardholder data exposure would be wrong and would undermine the whole finding.
3. You have confirmed read access to order records. What do you do, and how is it reported?
Read the worked answer
The engagement says stop and notify - do it before doing anything else, in writing, stating what was accessed, when, how many records, and what has been retained.
Minimize. Do not pull rows beyond what proves the finding. If a single row is needed as evidence, mask every field except a non-identifying fragment, store it in the encrypted engagement share with access limited to the tester and engagement lead, and hash it for integrity. The count from COUNT(*) and the column list carry the same evidential weight as an actual dump.
Legal framing. Your access is processing of personal data on the client's behalf and is governed by the data-processing terms in the contract, including retention and deletion. Whether the client has a notification duty is their decision, made with counsel - an authorized test is usually not a notifiable breach, but the client must make that call, and they cannot make it if they learn about it in the final report three weeks later.
Reporting. Describe by class and count: 'unauthenticated SQL injection in the sort parameter yields read access to the 300,000-record orders table and write access to order and price records.' Give the reproduction path so the engineers can verify the fix, and define the retest criterion up front: the parameter is bound rather than concatenated, malformed input returns 400, and the WAF rule is updated in the same change so the fix is not dependent on the WAF alone. Rate the severity on data sensitivity and business impact, not on whether shell access was achieved.