Relational databases
sqlmap

sqlmap is an open source penetration testing tool that automates the detection and exploitation of SQL injection vulnerabilities. It is widely used by security professionals to test whether a web application is vulnerable before an attacker finds the weakness first.

Understanding how sqlmap works also makes you a better developer: when you see what it can extract from a vulnerable application, the importance of parameterized queries becomes very concrete.

Ethical use only. Only run sqlmap against systems you own or have explicit written permission to test. Running it against any other system is illegal and unethical regardless of intent.
What is SQL Injection?

SQL injection occurs when user-supplied input is concatenated directly into a SQL query instead of being passed as a parameter. The attacker can then manipulate the query structure to bypass authentication, read arbitrary data, or modify the database.

A classic vulnerable Node.js/Express example:

// VULNERABLE — never do this
app.get('/user', async (req, res) => {
  const id  = req.query.id;
  const sql = "SELECT * FROM users WHERE id = " + id;
  const result = await pool.query(sql);
  res.json(result.rows);
});

If the URL is /user?id=1 the query is normal. But if an attacker sends /user?id=1 OR 1=1, the query becomes:

SELECT * FROM users WHERE id = 1 OR 1=1

This returns all rows. With more advanced payloads, an attacker can read any table, extract password hashes, or determine the entire database schema.

Setting Up a Test Environment

Never test against a live application. Use a deliberately vulnerable practice application instead. Two popular options:

Both run locally. DVWA is PHP/MySQL-based so it fits naturally alongside the rest of this course. After installation, set the security level to Low in DVWA settings to make the SQL injection exercises exploitable.

Installing sqlmap

sqlmap requires Python 3. Download it from https://sqlmap.org or clone the repository:

git clone https://github.com/sqlmapproject/sqlmap.git

Run it with:

python sqlmap.py --help

On Linux/macOS sqlmap is often available directly via the package manager:

sudo apt install sqlmap   # Debian/Ubuntu
brew install sqlmap       # macOS
Basic Usage

The most common starting point is testing a URL parameter. The -u flag specifies the target URL. sqlmap will try various payloads against each parameter and report which ones are injectable.

python sqlmap.py -u "http://localhost/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit" --cookie="PHPSESSID=abc123;security=low"

If sqlmap finds a vulnerability it will show the injection type and the database type. You can then ask it to enumerate further:

FlagWhat it does
--dbsList all databases on the server
-D dbname --tablesList all tables in a database
-D dbname -T tablename --columnsList columns in a table
-D dbname -T tablename --dumpDump all rows from a table
--current-userShow the database user sqlmap is running as
--current-dbShow the current database
--level=3Increase test depth (1–5, default 1)
--risk=2Allow riskier payloads (1–3, default 1)
--batchRun non-interactively, accept all defaults

Example: list all databases after confirming injection:

python sqlmap.py -u "http://localhost/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit" --cookie="PHPSESSID=abc123;security=low" --dbs --batch
Testing a POST Form

For login forms and other POST requests, capture the request with a browser's developer tools or Burp Suite, save it to a file, and pass it with -r:

python sqlmap.py -r request.txt --batch --dbs

The request file looks like a raw HTTP request:

POST /login HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded

username=admin&password=test

sqlmap will test each POST parameter for injection.

What the Results Tell You

When sqlmap successfully exploits an injection point, it can typically retrieve:

  • All database names on the server
  • All table and column names
  • All data rows — including usernames, password hashes, email addresses
  • The database software version and operating system
  • In some configurations: read local files or execute OS commands

Against a typical poorly secured application, a full dump of the users table takes seconds. This is why even a single unparameterized query is a critical vulnerability.

How to Prevent SQL Injection

The fix is always the same: never concatenate user input into SQL. Use parameterized queries (prepared statements) so the database driver always treats user input as data, never as SQL syntax.

Vulnerable (Node.js/Express):

app.get('/user', async (req, res) => {
  const result = await pool.query(
    "SELECT * FROM users WHERE id = " + req.query.id
  );
  res.json(result.rows);
});

Safe (Node.js/Express + PostgreSQL):

app.get('/user', async (req, res) => {
  const result = await pool.query(
    'SELECT * FROM users WHERE id = $1',
    [req.query.id]
  );
  res.json(result.rows);
});

Safe (Node.js/Express + SQL Server):

app.get('/user', async (req, res) => {
  const result = await pool.request()
    .input('id', sql.Int, req.query.id)
    .query('SELECT * FROM users WHERE id = @id');
  res.json(result.recordset);
});

In all cases the database driver sends the query and the parameters separately. No matter what the user supplies, it cannot change the query structure.



Toggle Menu