Injection: SQL Injection and Command Injection
CAP, ACID vs BASE, latency numbers, back-of-envelope estimation, single points of failure — the vocabulary every system designer thinks in.
Core Philosophy: The deepest flaw in all of software security is the confusion between data and code. When an application takes input that should be plain data and accidentally lets it be executed as a command, the attacker can rewrite what the application does. Injection is that flaw. It is decades old, endlessly patched, and still everywhere — because the mistake that causes it is so easy to make.
Part 1: The Problem
Applications constantly build commands out of pieces — a database query assembled from a search term, a system command built with a filename. If the application builds those commands by gluing untrusted user input directly into a command string, then a cleverly crafted input stops being treated as data and starts being treated as part of the command.
That is injection. The user input “injects” new meaning into the command. It’s the root of SQL injection, command injection, and — as you’ll see in 2.5 — cross-site scripting too. This section uses the most classic example, SQL injection, to teach the underlying idea.
Part 2: The Concept — Data vs Code Confusion
Here is the entire vulnerability in one picture. An application wants to look up a user by name. It builds a database query:
THE INTENDED QUERY (input treated as DATA):
SELECT * FROM users WHERE name = 'alice'
└──┬──┘
the user's input — just data
The app built it by gluing strings together:
"SELECT * FROM users WHERE name = '" + INPUT + "'"
Now an attacker enters, as the “name”, this input:
' OR '1'='1
The application glues it in exactly as before, and the query becomes:
SELECT * FROM users WHERE name = '' OR '1'='1'
└──────┬──────┘
this is now part of the QUERY LOGIC
The input’s quote ' closed the string early, and OR '1'='1' — which is always true — was injected as logic. The query now returns every user. The input stopped being data and became code.
┌─────────────────────────────────────────────────┐
│ The flaw: the app could not tell the │
│ attacker's CODE apart from ordinary DATA, │
│ because it built the command as a raw string. │
└─────────────────────────────────────────────────┘
That’s injection. Every variant is this same confusion in a different context.
Part 3: SQL Injection — Types and Impact
SQL is the language applications use to talk to databases. SQL injection (SQLi) is injection into a database query. Because the database holds the application’s most valuable asset — the data — SQLi is severe.
What an attacker can achieve with SQLi, depending on the flaw:
- Read data they shouldn’t — dump entire tables: users, passwords, payment info.
- Bypass authentication — the classic
' OR '1'='1style input in a login form. - Modify or delete data — change records, drop tables.
- Sometimes, full server compromise — some databases allow command execution.
SQLi comes in flavours, defined by how the attacker gets the answer back:
| Type | How it works |
|---|---|
| In-band / classic | Results come back directly in the app’s response — the easiest to exploit. |
| Blind SQLi | The app’s response doesn’t show data directly, but its behaviour differs (a different page, an error, a true/false reaction). The attacker asks yes/no questions and reconstructs data bit by bit. |
| Time-based blind | Even behaviour looks identical — so the attacker injects a command telling the database to pause if a condition is true, and reads the answer from the response delay. |
Blind techniques feel like magic at first; they’re really just patient yes/no questioning. You’ll see them in the lab.
Part 4: Command Injection — The Same Flaw, a Different Context
Command injection (or OS command injection) is the same data-vs-code confusion, but the command being built is an operating-system command instead of a database query.
If an application takes user input and glues it into a system command — say, a tool that pings an address the user supplies:
INTENDED: ping -c 1 <user-supplied address>
Attacker supplies: 8.8.8.8 ; cat /etc/passwd
BECOMES: ping -c 1 8.8.8.8 ; cat /etc/passwd
└────────┬───────┘
a SECOND command, injected
The ; ends the first command and the attacker’s own command runs next — now they’re executing commands on the server’s operating system. Command injection is especially dangerous because it can lead directly to control of the server.
The lesson: injection is a family. SQLi, command injection, and others are all the same root cause — untrusted input glued into a command — in different languages. Recognize the pattern and you’ll spot injection anywhere.
Part 5: Finding Injection — The Testing Mindset
How do you actually find injection in an application? You think like section 1.2 taught — “what if I send something unexpected?” — and you test systematically.
1. FIND THE INPUTS Every place input reaches the app:
form fields, URL parameters, headers,
cookies, JSON values, file uploads.
2. PROBE Into each input, send characters that are
SPECIAL in the target command language —
for SQL, a single quote ' is the classic.
3. OBSERVE Watch the response. A database error after
you send a quote is a strong signal the
input reaches a query unsafely.
4. CONFIRM Craft an input that proves you can change
the command's logic (carefully — see the
ethics note below).
5. ASSESS Determine the real impact: what can actually
be read, changed, or executed.
A database error message appearing because you typed a single quote is one of the most classic “this might be injectable” signals in all of web security.
⚖️ Ethics of confirming injection. When testing — even on an authorized target — prove the vulnerability exists; do not exploit it destructively. Demonstrate you can read data; don’t dump the entire customer database. Never use aDELETEorDROPto “test.” On a bug bounty target, a careful proof-of-concept is what you report; pillaging the database is a crime even if the program is in scope. This is the responsible-disclosure discipline from page 1.0, applied.
Part 6: Tools, and a Glance at the Fix
Automated tools. Tools like sqlmap can detect and exploit SQL injection automatically — finding injectable parameters, identifying the database, extracting data. They’re powerful, and you’ll use them. But two cautions: first, understand the vulnerability manually before leaning on automation — a tool you don’t understand produces results you can’t interpret or trust. Second, automated tools are aggressive; on a real engagement, their default behaviour can be too noisy or destructive. Use them deliberately, within scope.
The fix — a preview of Phase 4.1. Injection has a clean, well-understood solution, and it’s worth knowing now even though you’ll implement it later. The fix is never build commands by gluing strings. Instead:
- Parameterized queries (prepared statements). The query structure is defined separately from the data. The data is sent to the database as data, in clearly marked slots — it can never be reinterpreted as query logic. This is the primary, decisive fix for SQLi.
- Input validation and using safe APIs that don’t mix data and code.
- For command injection: avoid calling OS commands with user input at all; if unavoidable, use safe APIs that pass arguments as a list, not a string.
VULNERABLE (string-building):
query = "SELECT * FROM users WHERE name = '" + input + "'"
SAFE (parameterized — structure and data kept separate):
query = "SELECT * FROM users WHERE name = ?"
execute(query, [input]) ← input can only ever be DATA
You’ll build these fixes properly in Phase 4.1, then re-attack your own code to prove they hold. For now, the key realization: injection is the data/code confusion, and the fix is keeping data and code rigorously separate.
📓 Key Terms
| Term | Plain meaning |
|---|---|
| Injection | Untrusted input being treated as code/commands rather than data. |
| SQL | The language applications use to query databases. |
| SQL injection (SQLi) | Injection into a database query. |
| In-band SQLi | SQLi where results return directly in the response. |
| Blind SQLi | SQLi inferred from the app’s behaviour, not direct output. |
| Time-based blind SQLi | Blind SQLi read from deliberate response delays. |
| Command injection | Injection into an operating-system command. |
| Parameterized query | A query where structure and data are kept strictly separate — the fix. |
| sqlmap | A tool that automates SQL injection detection and exploitation. |
🧪 Hands-On Lab
Strictly on your own lab or a deliberately vulnerable practice app. SQL injection against any unauthorized system is a serious crime.
Task 1 — Set up a deliberately vulnerable app. Use a known intentionally vulnerable web application (several exist specifically for this; some are pre-installed on Kali, others run in a container). These have SQL injection challenges built in.
Task 2 — Trigger your first SQLi signal. Find an input that reaches a database query (a login form or a search box). Enter a single quote '. Watch for a database error in the response. That error is the classic “injectable” signal from Part 5.
Task 3 — Bypass a login. On a deliberately vulnerable login form, craft an input (the ' OR '1'='1 family from Part 2) that logs you in without valid credentials. Watch the intended query get rewritten. Understand exactly why it worked — that understanding is the whole point.
Task 4 — Extract data, carefully. On a vulnerable search/listing page, use SQL injection to retrieve data the page wasn’t meant to show. Practice demonstrating the issue — retrieve enough to prove it — rather than dumping everything. Build the responsible habit now.
Task 5 — Experience blind SQLi. Find a blind SQLi challenge. Exploit it by asking yes/no questions through the app’s behaviour. It’s slow and methodical — that’s the lesson: blind injection is patience, not magic.
Task 6 — Run sqlmap, then reflect. Point sqlmap at a vulnerable parameter in your lab and watch it work. Then ask yourself: do you understand what it did and why? If not, go back to the manual tasks. The tool should confirm your understanding, not replace it.
Task 7 — Try command injection. Find a command-injection challenge (a “ping a host” style feature is common). Inject a second command. See the data/code confusion in an OS-command context.
⚠️ Common Mistakes
- Leaning on sqlmap before understanding SQLi manually. A tool’s output is meaningless if you can’t interpret it. Learn the vulnerability by hand first.
- Destructive “testing.” Never use
DELETE/DROPor dump entire databases to “prove” a bug. Demonstrate carefully. On real targets, over-exploitation is a crime regardless of scope. - Thinking injection is only SQL and only login forms. Injection lives in any input — URL parameters, headers, cookies, JSON, file names — and in many command languages. Test everything.
- Missing blind injection. No error and no visible data doesn’t mean “not vulnerable.” Behaviour-based and time-based blind SQLi are real and common.
- Believing input filtering (blacklisting bad characters) is the fix. Attackers bypass filters endlessly. The real fix is parameterized queries — separating data from code structurally.
✅ Recap & What’s Next
- Injection is the core software-security flaw: untrusted input glued into a command gets executed as code instead of data.
- SQL injection attacks database queries (in-band, blind, time-based); command injection is the same flaw against OS commands — both can be devastating.
- The decisive fix is parameterized queries — keeping command structure and data strictly separate — which you’ll build in Phase 4.1.
Next (2.5): We stay with injection, but move the battleground into the victim’s browser. Cross-Site Scripting is injection of malicious JavaScript — and it turns a user’s own browser against them.
⁂ Back to all modules