👨🏻‍💻Securing Your Web Applications from SQL Injection with SQLMap
Tags: sql, security, beginners, web
Published: 2023-06-10 11:46:02

<small>[Cover image by Pete Linforth](https://pixabay.com//?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=4084717)</small>

## Table of Contents
1. [What is SQL injection](#what-is-sql-injection)
    1. [A practical example of SQL injection](#a-practical-example-of-sql-injection)
2. [SQLMap: Automated SQLi testing](#sqlmap-automated-sqli-testing)
    1. [Routes protected by authorization](#routes-protected-by-authorization)
    2. [Slowing down queries](#slow-down-queries)
    3. [Enumerating the database](#enumeratin-the-database)
3. [Protecting against SQLi](#protecting-against-sqli)
    1. [Prepared query](#prepared-query)
    2. [Sanitize and escape user input](#sanitize-and-escape-user-input)
4. [Legally test SQLMap on intentionally injectable websites](#legally-test-sqlmap-on-intentionally-injectable-websites)

# What is SQL injection

SQL injection is a way for attackers to change the queries that interact with the database and _**"inject"**_ their own queries. A typical example is a query that has been composed from concatenation which includes user inputed variables. 

```sql
$q = "SELECT * FROM users WHERE id = " . $_GET['id'];
```

The above query can be _**"injected"**_ through the $_GET["id"] parameter. 

SQL injection is still one of the most common ways to penetrate a website. A study from 2019 shows that **29% of websites are still susceptible to sql injection attacks**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ot3dgbwnxv3tyii7jzox.png) <small>Credit: [Web Application vulnerabilities and threats : statistics for 2019](https://www.ptsecurity.com/ww-en/analytics/web-vulnerabilities-2020/)</small>

## A practical example of SQL injection

The above SQL code might run by doing a GET reques to

```
https://example.com/article?id=1
```

So it expects id to be 1. Which would result in the SQL query to be:

```sql
$q = "SELECT * FROM users WHERE id = 1";
```

However, if we think smart about it we know that we can extend the query to return more results. 

If instead of 1 we would write something like **1 or 1 = 1** the query would extend and we would be able to get all user information from the database. The request would look like that: 

```
https://example.com/article?id=1 or 1=1
```

and the query:

```
$q = "SELECT * FROM users WHERE id = 1 or 1=1";
```

## SQLMap: Automated SQLi testing

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wa0trygq8ct2dtls3z64.png)

There are many types of SQLinjection and it would take an awful amount of time to check for all types of SQLi against a target. This is why SQLMap was created. It automates the process of testing. 

To download SQLMap if you are on Linux distribution you can type.

```
sudo apt install sqlmap
```

For **Windows** you can download the github version

```
git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
```

Keep in mind that you need to have python downloaded in your machine as well to run sqlmap.

SQLMap comes with a plethora of parameters and flags that we will explore in this article. 

To start we will see a simple attack to a certain endpoint. We need to use the -u parameter to set the endpoint.

```
sqlmap -u "https://example.com/articles?id=1"
```

This will test a single endpoint for sql injection. However we still need to press "Y" on everything. This is sometimes useful but most times it is better to just go with the default behavior to speed up the process so you can add the --batch parameter.

```
sqlmap -u "https://example.com/articles?id=1" --batch
```

This speeds up the process a bit. However you still need to manually test every single endpoint and most websites have more than just 5 or 10 endpoints to test. So we would need a tool that let's us **crawl** through the links of the website and perform sql injection when it sees parameters sent to the backend. 

Luckily SQLMap has a --crawl=<Integer> parameter which does exactly that. Depending on the value it will crawl down as many directories from the root of the website.

```
sqlmap -u "https://example.com/articles?id=1" --batch --crawl=2
```

SQLmap starts living up to its name as we are actually truly automating the process. However we are not done yet. We can speed the process up a bit more by adding the --smart flag. This flag performs SQLi only if it finds positive heuristics. By adding --smart most endpoints will not be tested at all for SQLi which will speed to the process tremendously. 

We can also add more threads so that more requests are executed if we are confident that the server can handle it by using the --threads=<Integer> flag. 

```
sqlmap -u "https://example.com/articles?id=1" --batch --crawl=2 --smart --threads=10
```

## Routes protected by authorization

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fwpj4lp61zshm6e7hesa.png)

Most web applications have routes that are protected by authorizations. This means that they can only be accessed if we have logged in for example. 

In typical PHP applications you can continue the session by sending a PHPSESSID cookie to the server.

In order to test the routes that are access after the log in has occurred we would need to add a --cookie="PHPSESSID=<String>" flag. The PHPSESSID can be found in Chrome under application > Cookies. 

```
sqlmap -u "https://example.com/articles?id=1" --batch --crawl=2 --smart --threads=10 --cookies="PHPSESSID=<String>"
```

## Slowing down requests

If you are testing on a live website and you don't want to disrupt it you can use the --delay=<Integer> flag which will delay each HTTP request by the <Integer> value.

## Enumerating the database

In this phase, after an SQLi has been found you can start enumerating the database to start seeing the users, databases, tables and column tables. 

Keep in mind that the speed in which he exploitation will take place depends a lot on the type of SQLi that has been found. 

**In-band SQLi**

> In-band SQL Injection occurs when an attacker is able to use the same communication channel to both launch the attack and gather results. (https://www.acunetix.com/websitesecurity/sql-injection2/)

This type of attack is very fast in comparison to

**Inferential SQLi (Blind SQLi)**

> an attacker is able to reconstruct the database structure by sending payloads, observing the web application’s response and the resulting behavior of the database server. (https://www.acunetix.com/websitesecurity/sql-injection2/)

With Blind SQLi you should focus more on extracting key databases and tables instead of trying to dump the whole database which will be impossible on most cases.

To start enumerating you can use the --dbs flag. This will show all the databases that are available. After choosing a database with the -D flag you would search in the same way for the tables with --tables and then choose a table using -T flag. 

```
sqlmap -u "https://example.com/<EXPLOITED URL> -D myapp -T users --dump"
```

With the above code you would dump the data from the table users 
 
# Protecting against SQLi

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/buov0qopuqjksseqpj9l.jpg) [Photo by Pixabay](https://www.pexels.com/photo/security-logo-60504)

## Prepared query

The easiest way to protect against SQL injections is to use prepared statements. Never concatenate user inputted parameters inside of SQL queries. For example the above query should be

```
$q = "SELECT * FROM users WHERE id = ?";
```

This would prevent SQL injection from happening.

## Sanitize and escape user input

If for whatever reason you are unable to make a prepared statement and you need to concatenate a string to a query you should be absolutely certain about what values make it inside the Query.

On our example above we can make sure that the $_GET parameter is sanitized and is always an integer before being used inside the query

```php
$s = (int) $_GET['id'];
```
In this way we can make sure that whatever the user is requesting will have to be an integer

You should escape the character when necessary as well. If the input is not strictly and integer and when it can be a string you should strip it to make sure the input will not escape the query.

```php
$s = addslashes($_POST['descr']);
```

# Legally test SQLMap on intentionally injectable websites

If you really want to test the tool online there are websites out there that are intentionally weak against SQLi attacks. http://testphp.vulnweb.com/ is one of them.

## Parrot Ctf

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kx8txyjbbs1nyxbemchc.png)

Parrot Ctf has a lot of free labs which let you test different hacking skills. Here is a lab that is specific [to SQLi](https://parrot-ctfs.com/dashboard/box.php?boxID=7330078175). 

# Conclusion

SQLMap is a powerful tool for exploiting security issues. Use it wisely, and use it legally on sites that you have permission to run tests on. Lights off, have a fun weekend!