Exploiting SQL Injection with Sqlmap

7 June 2021 - Articles
Back

We’ve previously posted about manually finding and exploiting SQL injection vulnerabilities. However one of the reasons SQL Injection is such a high risk vulnerability overall if due to the fact that exploitation can often be entirely automated. One tool for exploiting this vulnerability is sqlmap. From the point of view of security testers, SQL Injection can be time consuming to exploit, especially with slow extraction methods such as Time-based blind. However by automating exploitation can allow security testers to demonstrate the issue risk whilst freeing up time to check other areas of the assessment scope.

So here’s a quick introduction to that tool, which is incredibly easy to use.

Injection

Basic Usage: GET Requests

The simplest usage for sqlmap is an injection point that is available as a GET request and requires no authentication, in this case you can simply supply the URL to SQLmap and it’ll churn through all of the parameters in the URL and eventually find the injection point, that’s as simple as:

python sqlmap.py -u "http://vuln.example.org/sql?id=123&page=10"

Here we’re invoking sqlmap as a python script – if you’re using Kali or another OS where all your tools are pre-installed you might be able to invoke it by calling sqlmap directly, but if you installed from git or a ZIP download the above command should be run from the extraction directory. Here we’ve given sqlmap a target URL and it’ll work its way through each parameter to determine if it’s vulnerable. If you believe that a specific options is vulnerable, you don’t have to wait for sqlmap to work its way through each parameter, you can specify one with the `-p` option, like this:

python sqlmap.py -u "http://vuln.example.org/sql?id=123&page=10" -p id

By default SQLmap will try to determine an injection point quickly and use the most common and safest options available to it, if you want it to try a little harder you can supply a level to increase the number of payloads it attempts and you can supply a risk to include more risky options such as benchmark(), whilst this may uncover an injection point it’ll also hurt the database a little bit and will potentially make it unavailable to legitimate users. There are five levels of additional payloads and three levels of risk:

python sqlmap.py -u "http://vuln.example.org/sql?id=123&page=10" --level 5 --risk 3

This will obviously make the search for injection points slower, but if you know the backend database type (for example if it’s been disclosed in a verbose error message) then you can increase the speed of the search by including the type within the command (Options here include: mssql, mysql, oracle, pgsql, sqlite, sqlite3 access, firebird, maxdb, sybase):

python sqlmap.py -u "http://vuln.example.org/sql?id=123&page=10" --dbms mssql

Additionally you can limit the types of injection that sqlmap uses by using the technique option, to limit it to Boolean, Error, Union, Stacked, Timed or some combination of those:

python sqlmap.py -u "http://vuln.example.org/sql?id=123&page=10" --technique E

Basic Usage: POST Requests

If your injection point is within a POST request and not a GET request then you can supply a request body by using the data option, like this:

python sqlmap.py -u "http://vuln.example.org/sql" --data "username=foo&password=bar"

Here the parameters are still accessible via the `-p` option used above, to specify a specific parameter for injection attempts.

Authentication and Cookies

If your injection point is only accessible with a valid login session you can supply a cookie value with the cookie option:

python sqlmap.py -u "http://vuln.example.org/sql" --cookie "PHPSESSID=foobar"

Complex and Custom Requests

If your request is a little more complex, like a multi-part post, you can supply a HTTP request in a text file. SQLmap will parse the file and select injection points or you can supply a specific injection point either with -p as above or by including {X} within the request file at the point you’d like to inject into.

python sqlmap.py -u "http://vuln.example.org/" -r httpreq.txt

Data Extraction

With the above you should get to a point that sqlmap has found a valid injection point, however it won’t go any further without a gentle kick, you can request that it extracts specific information from the database. You can request a list of databases, tables or columns with –dbs, –tables and –columns. Like this:

python sqlmap.py -u "http://vuln.example.org/sql?id=123&page=10" --dbs

This will cause sqlmap to output a list of databases, tables, or columns as appropriate and you can select a specific one by using -D, -T and -C. However to cause it to actually extract rows from the database you need to give it the dump option. So once you’ve chosen a target you can go ahead and dump data like this:

python sqlmap.py -u "http://vuln.example.org/sql?id=123&page=10" -D mainapp -T tblUsers -C username,password --dump

If your extraction is running a little slow, try adding threads 10 to the end to increase speed through threading!

python sqlmap.py -u "http://vuln.example.org/sql?id=123&page=10" -D mainapp -T tblUsers -C username,password --dump --threads 10

Advanced

Automate Searching the Database

If your target database is too large, or your extraction speed is too low to run a full enumeration you can quickly search for a useful column using the search option, so to look for columns such as pass, passwd, passcode and password you could use the following search command:

python sqlmap.py -u "http://vuln.example.org/sql?id=123&page=10" -C pass --search

It’ll prompt you to see if you want to search for columns that exactly match “pass” or simply have “pass” in them (such as password).

Filter Evasion: Tamper Scripts

If your target application is protected by simple user input filtering, sqlmap can also automate filter evasion through the user of “tamper scripts” these take the standard payloads it would normally use and modify them before sending them. For example if your target application filters the word “UNION” and “union” you could potentially bypass this by changing the request to “uNiOn” (yeah flipping case like this is surprisingly effective against naïve filters!) or perhaps whitespace is filtered – then you can bypass this filter by using comments, which are the equivalent in many SQL contexts. You can apply these scripts like this:

python sqlmap.py -u "http://vuln.example.org/sql?id=123&page=10" --tamper randomcase 
python sqlmap.py -u "http://vuln.example.org/sql?id=123&page=10" --tamper space2comments

Take a look in the “tamper” folder of your sqlmap installation for a full list of available scripts and a little filter evasion inspiration!

Difficult Injection Points

If your injection point is protected by CSRF tokens, or requires some complex pre-injection steps to be conducted first (such as if the injection point is within a delete function which requires a create step to be executed first) you could always consider pushing SQLmap through Burp suite with the proxy option and utilising Burp extensions to handle the complexity for you!

python sqlmap.py -u "http://vuln.example.org/sql?id=123&page=10" --proxy http://localhost:8080

Defending against Injection

SQL injection comes about because user input is insecurely concatenated into a SQL query. So there’s two things to note here, the first is concatenation and the fix here is instead to use “parametrized” or “prepared” statements, these are available in all modern languages and frameworks, these effectively separate the query from the user input so that the database cannot mix the two up and effectively stop SQL injection attacks on their own. An example for PHP can be found in the PHP documentation here, which gives a flavour of the general idea.

However another thing to consider, to stop other kinds of injection and web application attack, it’s a good idea to consider filtering all user input.

That’s it!

Play Cover Track Title
Track Authors