Investigating Web Application SQL Injection via Apache Logs
Log analysis and triage of blind Boolean-based SQL injection attempts against a vulnerable plugin endpoint on a WordPress web server.
Lab Environment: Executed on an isolated local web server running a deliberately vulnerable WordPress plugin in an educational sandboxed environment.
Executive Summary
Analysis of Apache access logs revealed an automated SQL injection probe directed at /wp-content/plugins/catalog-view/ajax-search.php?cat_id=1. The attacker submitted nested UNION SELECT and SLEEP(5) payloads. The backend database server experienced intermittent query stalls. The vulnerable script passed unescaped user input directly into a mysqli_query() string.
Scenario & Trigger
A monitoring alert reported a 400% spike in HTTP 500 response codes and response latency spikes on a staging e-commerce website.
Endpoint: /wp-content/plugins/catalog-view/ajax-search.php ResponseTime: >5.2s HTTP_Status: 500 RequestCount: 184Initial Evidence
- Vulnerable URI: /wp-content/plugins/catalog-view/ajax-search.php
- Attacker IP: 203.0.113.194 (Tor exit node)
- Observed Parameter: cat_id
- Sample Payload: cat_id=1%27%20AND%20(SELECT%206212%20FROM%20(SELECT(SLEEP(5)))a)--%20-
Investigation Methodology & Narrative
Step 1: Examined /var/log/apache2/access.log for requests containing URL-encoded single quotes (%27), UNION, and SLEEP keywords.
Step 2: Traced requests from IP 203.0.113.194. Observed an automated fingerprinting sequence starting with basic quote injection followed by time-based blind SQLi payloads.
Step 3: Inspected the PHP source code of ajax-search.php. Located line 24: $res = mysqli_query($conn, "SELECT * FROM wp_catalog WHERE category_id = " . $_GET['cat_id']);. Zero parameterization or input sanitization was implemented.
Step 4: Checked database audit logs. Verified the queries timed out or failed with syntax errors; no customer table records or administrator password hashes were extracted before the IP was blocked.
Incident Timeline
| Time (UTC) | Event | Telemetry Source | Analyst Note |
|---|---|---|---|
| 16:38:12 UTC | Initial single quote probe submitted | access.log | Server returned HTTP 500 due to unhandled SQL syntax error |
| 16:40:05 UTC | Automated tool initiates time-based blind SQLi probes | access.log | SLEEP(5) payload caused 5.02-second response delays |
| 16:42:00 UTC | Latency alert triggered in monitoring system | APM Monitor | Analyst joined investigation |
| 16:50:00 UTC | WAF virtual patch applied to block SQL keywords on cat_id parameter | ModSecurity / Cloudflare WAF | Immediate mitigation applied while developer prepared patch |
Indicators of Compromise (IOCs)
| Type | Observed Value | Context | Reputation |
|---|---|---|---|
| IPv4 | 203.0.113.194 | Source IP for automated SQL injection scanner (Tor node) | Malicious |
| URL | hxxp://site-lab[.]local/wp-content/plugins/catalog-view/ajax-search.php?cat_id=1 | Vulnerable endpoint targeted | Suspicious |
Log Analysis & Telemetry Dissection
203.0.113.194 - - [02/Aug/2026:16:38:12 +0000] "GET /wp-content/plugins/catalog-view/ajax-search.php?cat_id=1' HTTP/1.1" 500 248 "-" "Mozilla/5.0"
203.0.113.194 - - [02/Aug/2026:16:40:05 +0000] "GET /wp-content/plugins/catalog-view/ajax-search.php?cat_id=1%27%20AND%20(SELECT%206212%20FROM%20(SELECT(SLEEP(5)))a)--%20- HTTP/1.1" 200 412 "-" "sqlmap/1.7"
203.0.113.194 - - [02/Aug/2026:16:40:11 +0000] "GET /wp-content/plugins/catalog-view/ajax-search.php?cat_id=1%20UNION%20ALL%20SELECT%20NULL,NULL,user_login,user_pass%20FROM%20wp_users--%20- HTTP/1.1" 500 248 "-" "sqlmap/1.7"Analysis Note: Clear evidence of progressive SQL injection probing, showing tool user-agent (sqlmap/1.7) and attempts to dump the wp_users table.
MITRE ATT&CK Mapping
| ID | Technique | Tactic | Observed Evidence |
|---|---|---|---|
| T1190 | Exploit Public-Facing Application | Initial Access | SQL injection targeting publicly reachable catalog-view endpoint |
Findings & Final Classification
Recommended SOC Response & Hardening
- •Refactor PHP endpoint to use prepared statements via PDO or WordPress $wpdb->prepare().
- •Cast incoming cat_id parameter strictly to integer: $cat_id = intval($_GET['cat_id']);.
- •Deploy ModSecurity Core Rule Set (CRS) or Cloudflare WAF managed ruleset to block common SQL injection vectors.
- •Audit remaining custom theme and plugin files for similar raw concatenation patterns.
Analyst Reflection: What I Learned
• Time-based blind SQL injection leaves distinct latency signatures in web server access logs (%D or %T formatting in Apache).
• Input type casting ($intval) and prepared statements provide complete immunity against SQL injection when consistently applied.