// 1 ZERO-DAY · 1 CVE · 1 EXPLOIT IN THE LAST 24H

Automating Discovery: sqlmap Against ShopBox with Defensive Monitoring

By Page 3 we had already walked through manual exploitation of ShopBox's order history endpoint—fingerprinting the MySQL backend on 192.0.2.20 with single-quote probes, confirming boolean-based blind injection with AND 1=1 versus AND 1=2, and extracting the database name character by character using SUBSTRING() and SLEEP(). That manual work matters because it builds intuition for what the database actually sees. But once you understand the vulnerability, repeating that labor by hand is wasteful. This is where sqlmap enters the picture—and where, as defenders, we need to understand exactly what its automation looks like from the other side of the connection.

sqlmap is an open-source penetration testing tool that automates SQL injection discovery and exploitation. It can be invoked as python sqlmap.py, python3 sqlmap.py, or simply sqlmap on Kali Linux [S4]. Before we begin, check your version:

sqlmap --version

Why this matters: Version output varies by installation source and time. If you're following along in the DeafNews lab, verify against the current release to ensure flag compatibility [S4].

Setting Up the Intercept Proxy

sqlmap's --proxy flag routes all traffic through a proxy server, letting us capture every request for later analysis [S3]. I run mitmproxy on my analysis workstation at 192.0.2.100 to create this visibility. mitmproxy is an interactive HTTPS proxy that records HTTP request/response pairs as "flows," each with a timestamp field and client_conn metadata [S1].

Start the proxy with options set via --set [S2]:

mitmproxy --set anticomp=true --set confdir=~/.mitmproxy -w shopbox_sqlmap.dump

The -w switch writes flows to shopbox_sqlmap.dump for later serialization [S6]. The anticomp=true option prevents mitmproxy from modifying compressed responses, preserving the exact bytes the application sends. I keep a dedicated configuration directory via --set confdir rather than polluting the default ~/.mitmproxy location [S2].

⚠️ Authorized, defensive use only. This proxy intercepts traffic to an isolated lab system with no external connectivity. Never run this configuration against production infrastructure without explicit authorization.

First sqlmap Run: Controlled Time-Based Detection

From Page 3, we know the order history endpoint at http://192.0.2.10/order_history.php is vulnerable, with the order_id parameter injectable. Rather than letting sqlmap try every technique—which generates excessive requests and can cause denial-of-service conditions [S5]—we constrain it to time-based blind injection only using --technique=T [S4][S5].

Time-based blind injection works by asking the database to delay its response when a condition is true. The attacker infers information from how long the server takes to reply, without seeing any data directly in the response. This is slower than boolean-based blind but works even when error messages and visible query differences are suppressed.

sqlmap -u "http://192.0.2.10/order_history.php?order_id=1001" \ --technique=T \ --dbms=mysql \ --proxy=http://192.0.2.100:8080 \ --batch

The --dbms=mysql flag narrows scope since we already fingerprinted the backend [S5]. --batch accepts default answers to all prompts, necessary for automation but risky in production—always review what defaults sqlmap selects for your version.

In plain terms: we're telling sqlmap "only use time delays, assume MySQL, send everything through my proxy, and don't ask me questions."

Watch mitmproxy's flow list. You'll see requests arriving in rapid succession, each with slightly different order_id values. sqlmap is probing: first establishing a time delay baseline, then injecting SLEEP() variants to confirm injection. The pattern is unmistakable—uniform intervals between requests, incrementing parameter values, and payloads containing SQL functions.

What the Logs Reveal

Now pivot to the defender's perspective. On 192.0.2.20, MySQL's general query log (if enabled) records every statement the server receives. The application access log on 192.0.2.10 records HTTP requests. The correlation between these two surfaces is where detection lives.

A typical sqlmap time-based probe generates queries like this in the general query log:

# illustrative output — verify on your target
SELECT * FROM orders WHERE order_id=1001 AND SLEEP(5)
SELECT * FROM orders WHERE order_id=1001 AND IF(ASCII(SUBSTRING((SELECT ...

The exact payload structure varies by sqlmap version and target, but the signature is consistent: nested SUBSTRING() calls, ASCII() conversions, and SLEEP() or BENCHMARK() delays. These are not queries any legitimate application generates.

On the application side, the access log shows the HTTP fingerprint:

# illustrative output — verify on your target
192.0.2.100 - - [14/Jan/2025:09:23:17 +0000] "GET /order_history.php?order_id=1001%20AND%20SLEEP%285%29 HTTP/1.1" 200 1423 "-" "sqlmap/1.x.x.xxxxxxxxxx (http://sqlmap.org)"

sqlmap's default User-Agent string is often left unchanged by junior testers—a gift to defenders, though easily modified with --user-agent. The request rate is the deeper signal: dozens of requests per minute to the same endpoint, each with a slightly mutated parameter, none followed by normal user navigation patterns.

Adding Evasion: What WAF Evasion Looks Like

Defensive tools often deploy a WAF (Web Application Firewall, a filter that inspects HTTP requests for malicious patterns). sqlmap includes tamper scripts that modify payload encoding to evade simple signature-based detection. The space2comment tamper replaces space characters with SQL comments (/**/), which many parsers accept but naive filters miss.

I want to stress: I cannot verify from our current sources that sqlmap's --tamper=space2comment behaves exactly as described in older documentation. Tamper script availability and effectiveness vary by version. Check your installation's tamper/ directory, and test behavior with --test-filter or equivalent version-specific verification.

Conceptually, the transformation looks like this:

Original payload After space2comment
AND SLEEP(5) AND/**/SLEEP(5)
UNION SELECT 1,2 UNION/**/SELECT/**/1,2

In mitmproxy, the proxy log shows the raw HTTP request with these substitutions intact. The WAF, if present, must decode and normalize before matching. Good WAFs do this; basic ones do not.

The defensive lesson: evasion is not magic. It is transformation that specific defenses fail to undo. Your detection should not rely on matching literal strings like AND SLEEP—it should look for structural anomalies like excessive URL-encoded characters in parameters, comment sequences in unusual contexts, or the behavioral pattern of rapid, similar requests.

Building the Detection Timeline

Let me walk through what I actually do when correlating these artifacts. I start with three data sources: mitmproxy's dump file, the application access log, and the MySQL general query log. Each captures a different layer, and their timestamps let me build a coherent narrative.

First, export mitmproxy flows to a workable format. The dump file written with -w can be processed using Python with json.dumps(flow.get_state()) [S6], or you can use mitmproxy's har_dump.py example for HAR-format output [S6]. I typically write a quick script to extract timestamp, method, URL, and User-Agent:

#!/usr/bin/env python3
# extract_mitm.py — illustrative script, verify against your mitmproxy version
import json, sys # mitmproxy flows serialized via flow.get_state()
for line in sys.stdin: flow = json.loads(line) req = flow.get("request", {}) print(f"{flow.get('timestamp','')} {req.get('method','')} {req.get('url','')} {req.get('headers',{}).get('User-Agent','')}")

Run against shopbox_sqlmap.dump, then sort and join with the application access log entries. The correlation is straightforward: matching source IP (192.0.2.100, my workstation), matching timestamps within network latency, and matching URL paths.

The MySQL general query log requires more interpretation. Time-based blind injection generates queries that execute successfully but take abnormal duration. I look for:

  • Queries with execution time significantly exceeding the application baseline
  • SLEEP(), BENCHMARK(), or GET_LOCK() function calls
  • Nested SUBSTRING()/ASCII()/ORD() patterns extracting single characters
  • Queries from the application database user that do not match known application query patterns

The timeline emerges as: 09:23:17 — first sqlmap probe arrives at proxy; 09:23:17.200 — same probe logged by application; 09:23:17.450 — corresponding query appears in MySQL general log with 5.2 second execution time; 09:23:22 — next probe arrives while previous still executing. This overlapping execution is characteristic: sqlmap does not wait for polite intervals; it fires requests as fast as the network allows, creating query queue pressure.

The Noise Signature

sqlmap can be very heavy on request volume and may cause excessive log growth [S5]. This is not a bug to work around; it is the detection signal. A skilled manual attacker paces probes, varies timing, and mimics legitimate traffic patterns. sqlmap's automation, by default, does none of this. The regularity itself becomes the anomaly.

From years of running both sides of this—attacking lab systems and then sifting through the aftermath—I have learned to watch for what I call "mechanical rhythm": requests arriving at consistent millisecond-level intervals, parameter values progressing in obvious sequences (1001, 1002, 1003... or more tellingly, ASCII values 65, 66, 67...), and the absence of any human browsing behavior like CSS or image requests between functional calls.

A Safer Re-run with Session Control

If you need to repeat this exercise—perhaps testing a new WAF rule or detection threshold—avoid accumulating stale session data that might skew results. sqlmap caches discovered injection points and database fingerprints between runs. While I cannot verify the exact flag syntax from our sources, check your version's help for session management options that clear or ignore previous state.

For controlled re-testing, I typically remove any .sqlmap directory or session files in the working directory, then re-run with explicit technique and DBMS constraints to prevent scope creep.

Key Takeaways for the Detection Surface

What sqlmap does What to look for in logs
Rapid sequential probes to single endpoint Request rate anomalies; missing interleaved assets
Time-based delays (SLEEP, BENCHMARK) Query execution time outliers in database logs
Character-by-character extraction SUBSTRING()/ASCII() patterns in SQL statements
Default or unmodified User-Agent Literal "sqlmap" strings (easily changed, so do not rely solely)
Tamper evasion (space-to-comment, etc.) Excessive URL encoding; comment sequences in parameters

The critical teaching point: automation is noisy and patterned [S5]. A determined human attacker will customize and slow their probes to evade threshold-based detection. sqlmap's default behavior will not. This makes it excellent for verifying that your detection pipeline actually fires—if you can catch sqlmap, you have a baseline. Catching patient manual attackers is harder, and covered later in Page 5's detection architecture discussion and Page 9's evasive attack analysis.

For now, ensure you can build the three-way correlation: proxy capture showing payload structure, application log showing request fingerprint, database log showing query execution. When these three align, you have a complete detection story—not just "something weird happened," but "this specific injection technique against this specific parameter caused this specific database behavior." That precision is what separates alert fatigue from actionable incident response.

Further reading