THM – SQL Injection – Part 12

Photo by Caspar Camille Rubin on Unsplash

This is my notes from the Junior Pentesting course at TryHackMe. This course takes you through the basics and some advanced topics regarding penetration testing.


What is a database?

A database is a way of electronically storing collections of data in an organised manner. A database is controlled by a DBMS which is an acronym for  Database Management System, DBMS’s fall into two camps Relational or Non-Relational, the focus of this room will be on Relational databases, some common one’s you’ll come across are MySQL, Microsoft SQL Server, Access, PostgreSQL and SQLite.

Within a DBMS, you can have multiple databases, each containing its own set of related data.

What are tables?

A table is made up of columns and rows, a useful way to imagine a table is like a grid with the columns going across the top from left to right containing the name of the cell and the rows going from top to bottom with each one having the actual data.

Columns:

Each column, better referred to as a field has a unique name per table. When creating a column, you also set the type of data it will contain, common ones being integer (numbers), strings (standard text) or dates. A column containing an integer can also have an auto-increment feature enabled; this gives each row of data a unique number that grows (increments) with each subsequent row, doing so creates what is called a key field, a key field has to be unique for every row of data which can be used to find that exact row in SQL queries.

ROWS:

Rows or records are what contains the individual lines of data. When you add data to the table, a new row/record is created, and when you delete data, a row/record is removed.

Relational vs Non-Relational Databases

A relational database, stores information in tables and often the tables have shared information between them, they use columns to specify and define the data being stored and rows to actually store the data. The tables will often contain a column that has a unique ID (primary key) which will then be used in other tables to reference it and cause a relationship between the tables, hence the name relational database.

Non-relational databases sometimes called NoSQL on the other hand is any sort of database that doesn’t use tables, columns and rows to store the data, a specific database layout doesn’t need to be constructed so each row of data can contain different information which can give more flexibility over a relational database.  Some popular databases of this type are MongoDB, Cassandra and ElasticSearch.

What is SQL?

SQL (Structured Query Language) is a feature-rich language used for querying databases, these SQL queries are better referred to as statements.

What is SQL Injection?

What is SQL Injection?
The point wherein a web application using SQL can turn into SQL Injection is when user-provided data gets included in the SQL query.

What does it look like?

The URL for each blog entry may look like this:

https://website.thm/blog?id=1

The web application retrieves the article from the database and may use an SQL statement that looks like the following:

SELECT * from blog where id=1 and private=0 LIMIT 1;

SQL statement above is looking in the blog table for an article with the id number of 1 and the private column set to 0.

Article 2 is locked as private

It cannot be viewed on the website. We could instead call the URL:

https://website.thm/blog?id=2;--

Which would then, in turn, produce the SQL statement:

SELECT * from blog where id=2;-- and private=0 LIMIT 1;

The semicolon in the URL signifies the end of the SQL statement, and the two dashes cause everything afterwards to be treated as a comment. By doing this, you’re just, in fact, running the query:

SELECT * from blog where id=2;--

In-Band SQLi

In-Band SQL Injection

In-Band SQL Injection is the easiest type to detect and exploit; In-Band just refers to the same method of communication being used to exploit the vulnerability and also receive the results

Error-Based SQL Injection

This type of SQL Injection is the most useful for easily obtaining information about the database structure as error messages from the database are printed directly to the browser screen. 

Union-Based SQL Injection

This type of Injection utilises the SQL UNION operator alongside a SELECT statement to return additional results to the page. This method is the most common way of extracting large amounts of data via an SQL Injection vulnerability.

Practical

The key to discovering error-based SQL Injection is to break the code’s SQL query by trying certain characters until an error message is produced; these are most commonly single apostrophes () or a quotation mark ( ).

1 UNION SELECT 1,2,3

This statement should produce an error message informing you that the UNION SELECT statement has a different number of columns than the original SELECT query. So let’s try again but add another column: 1 UNION SELECT 1,2

Success, the error message has gone, and the article is being displayed, but now we want to display our data instead of the article.

0 UNION SELECT 1,2,3

You’ll now see the article is just made up of the result from the UNION select returning the column values 1, 2, and 3. We can start using these returned values to retrieve more useful information. First, we’ll get the database name that we have access to:

0 UNION SELECT 1,2,database()

You’ll now see where the number 3 was previously displayed; it now shows the name of the database, which is sqli_one.

Our next query will gather a list of tables that are in this database.

0 UNION SELECT 1,2,group_concat(table_name) FROM information_schema.tables WHERE table_schema = ‘sqli_one’

The method group_concat() gets the specified column (in our case, table_name) from multiple returned rows and puts it into one string separated by commas. The next thing is the information_schema database; every user of the database has access to this, and it contains information about all the databases and tables the user has access to. In this particular query, we’re interested in listing all the tables in the sqli_one database, which is article and staff_users. 

As the first level aims to discover Martin’s password, the staff_users table is what is of interest to us. We can utilise the information_schema database again to find the structure of this table using the below query.

0 UNION SELECT 1,2,group_concat(column_name) FROM information_schema.columns WHERE table_name = 'staff_users'

This is similar to the previous SQL query. However, the information we want to retrieve has changed from table_name to column_name, the table we are querying in the information_schema database has changed from tables to columns, and we’re searching for any rows where the table_name column has a value of staff_users.

This is similar to the previous SQL query. However, the information we want to retrieve has changed from table_name to column_name, the table we are querying in the information_schema database has changed from tables to columns, and we’re searching for any rows where the table_name column has a value of staff_users.

0 UNION SELECT 1,2,group_concat(username,’:’,password SEPARATOR ‘<br>’) FROM staff_users

Again we use the group_concat method to return all of the rows into one string and to make it easier to read. We’ve also added ,’:’, to split the username and password from each other. Instead of being separated by a comma, we’ve chosen the HTML <br> tag that forces each result to be on a separate line to make for easier reading.

Blind SQLi – Authentication Bypass

Blind SQLi
Blind SQLi is when we get little to no feedback to confirm whether our injected queries were, in fact, successful or not, this is because the error messages have been disabled, but the injection still works regardless.

Authentication Bypass

Login forms that are connected to a database of users are often developed in such a way that the web application isn’t interested in the content of the username and password but more whether the two make a matching pair in the users table. In basic terms, the web application is asking the database “do you have a user with the username bob and the password bob123?”, and the database replies with either yes or no (true/false) and, depending on that answer, dictates whether the web application lets you proceed or not. 

Practical

‘ OR 1=1;–

This turns the SQL query into the following:

select * from users where username='' and password='' OR 1=1;

Blind SQLi – Boolean based

Boolean based

Boolean based SQL Injection refers to the response we receive back from our injection attempts which could be a true/false, yes/no, on/off, 1/0 or any response which can only ever have two outcomes. That outcome confirms to us that our SQL Injection payload was either successful or not.

Practical

select * from users where username = ‘%username%’ LIMIT 1;
The browser body contains the contents of {“taken”:true}. This API endpoint replicates a common feature found on many signup forms, which checks whether a username has already been registered to prompt the user to choose a different username. Because the taken value is set to true, we can assume the username admin is already registered. In fact, we can confirm this by changing the username in the mock browser’s address bar from admin to admin123, and upon pressing enter, you’ll see the value taken has now changed to false.

admin123′ UNION SELECT 1;– 

Keeping the username admin123 we can start to append to this to try and make the database confirm true things.

As the web application has responded with the value taken as false, we can confirm this is the incorrect value of columns. 

admin123′ UNION SELECT 1,2,3 where database() like ‘%’;–

We get a true response because, in the like operator, we just have the value of %, which will match anything as it’s the wildcard value. If we change the wildcard operator to a%, you’ll see the response goes back to false, which confirms that the database name does not begin with the letter a.

We’ve established the database name (sqli_three), which we can now use to enumerate table names using a similar method by utilising the information_schema database.

admin123′ UNION SELECT 1,2,3 FROM information_schema.tables WHERE table_schema = ‘sqli_three’ and table_name=’users’;–

We discovered a table in the sqli_three database named users, which you can be confirmed by running the following username payload above.

admin123' UNION SELECT 1,2,3 FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='sqli_three' and TABLE_NAME='users' and COLUMN_NAME like 'a%';

We now need to enumerate the column names in the users table so we can properly search it for login credentials. Again, using the information_schema database and the information we’ve already gained, we can start querying it for column names. Using the payload below, we search the columns table where the database is equal to sqli_three, the table name is users, and the column name begins with the letter a.

admin123' UNION SELECT 1,2,3 FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='sqli_three' and TABLE_NAME='users' and COLUMN_NAME like 'a%' and COLUMN_NAME !='id';

Repeating this process three times will enable you to discover the columns id, username and password. Which now you can use to query the users table for login credentials. First, you’ll need to discover a valid username which you can use the payload below:

admin123' UNION SELECT 1,2,3 from users where username like 'a%

Which, once you’ve cycled through all the characters, you will confirm the existence of the username admin. Now you’ve got the username. You can concentrate on discovering the password. The payload below shows you how to find the password:

admin123' UNION SELECT 1,2,3 from users where username='admin' and password like 'a%

Cycling through all the characters, you’ll discover the password is 3845.

Blind SQLi – Time Based

A time-based blind SQL there are no visual indicator of your queries being wrong or right. Instead, your indicator of a correct query is based on the time the query takes to complete. This time delay is introduced by using built-in methods such as SLEEP(x) alongside the UNION statement. The SLEEP() method will only ever get executed upon a successful UNION SELECT statement. 

referrer=admin123′ UNION SELECT SLEEP(5),2 where database() like ‘u%’;–

Similar Posts