1. Project Definition

1.1 Introduction

SQL Injections (SQLi) and Cross-Site Scripting (XSS) are two types of web vulnerabilities stemming from very similar root causes: insufficient sanitization of user-supplied inputs, which allows these inputs to be interpreted by the application as executable code.

Both vulnerabilities are extremely dangerous to the security of both the server and the application's users. Identifying them across all their variants is imperative for any developer, system administrator, and/or security analyst. The existence of either vulnerability directly threatens confidentiality, availability, integrity, and authentication against anyone capable of exploiting them.

1.2 Project Approach

This project consists of developing a web environment intentionally designed to be vulnerable to both SQL Injection (SQLi) and Cross-Site Scripting (XSS). The goal is to provide users with an easy way to experiment within a controlled environment where they can safely test different attack vectors, exploitation practices, and mitigation techniques. This educational framework within the cybersecurity field is designed to make the behavior of a vulnerable application easy to understand.

1.3 Project Objectives

The objective of this project is to build a laboratory environment where users can experiment with different types of SQL and XSS injections, as well as their defenses, within a controlled space. It also aims to clarify their symptoms, behavior, and the various exploitation techniques utilized by threat actors.

To facilitate experimentation, the running database query must be visible to the user on the web application at all times.

All injections must be executable directly from the web application in a straightforward and visual manner, without requiring external software such as Burp Suite or Caido to perform the injection.

The application must be easily deployable using Docker.

Users will be able to enable and disable certain defense mechanisms external to the application's native security, such as mod_security.
In summary, the intent of this project is to develop a didactic, vulnerable environment to experiment with the aforementioned flaws—ensuring it is easy to use and understand for research and study purposes.

Additionally, it defines guidelines and best practices to help a system administrator limit the blast radius of an SQL injection.

Finally, it includes the development of an educational document detailing the step-by-step exploitation process for the various types of vulnerabilities found within the application.

1.4 Tools and Technologies Used

  • PHP
  • The application will be developed using PHP, a server-side language capable of interacting with databases.
  • Apache
  • Apache will be used to deploy and serve the web environment.
  • MariaDB/MySQL
  • MySQL/MariaDB will be the database engine running in the environment.
  • HTML
  • HTML will be used to define the web page structure and the input forms.
  • CSS
  • A styles.css file will be used to style and improve the visual layout of the web application.
  • Docker Compose
  • The LAMP stack will be deployed via Docker Compose by default to simplify setup and avoid threatening the security of the host operating system.
  • Python
  • Python scripts will be utilized to automate and facilitate the exploitation of certain complex vulnerabilities found in the application.
  • mod_security
  • An Apache module integrated with the OWASP Core Rule Set (CRS) that acts as a Web Application Firewall (WAF). This module is used to apply external protection layers to the vulnerable application, allowing users to experiment with its effects and behavior during an active attack sequence.

2. Key Terms

  • SQLi: SQL Injection. A vulnerability that allows an attacker to execute arbitrary code or commands within a database engine.
  • XSS: Cross-Site Scripting. A vulnerability that allows an attacker to inject malicious client-side scripts into a web application, which are later executed by the browsers of other users visiting the site.
  • LAMP: A web stack acronym composed of Linux, Apache, MySQL, and PHP.
  • Injection: A technique consisting of inserting malicious code inputs into an application's data flow.
  • Exfiltration: The unauthorized extraction of data or sensitive information from a system.
  • Principle of Least Privilege: A core security practice that entails granting users and services only the absolute minimum access levels and permissions necessary to perform their tasks.
  • Authentication: The process of verifying the digital identity of a user or system entity.
  • Sanitization: The process of filtering, cleaning, or escaping inputs to prevent them from being interpreted as executable code.
  • Web Application Firewall (WAF): A specialized firewall operating at the application layer that protects web servers (like Apache or Nginx) by inspecting and filtering HTTP/HTTPS requests based on a defined set of security rules.

3. Project Development

3.1 Docker LAMP Environment

To build this environment, I will require 3 distinct Docker containers:

  • php:8.3-apache

    This container forms the web routing layer of our environment. By default, it exposes ports 80 and 443 to the host machine, although users can access it locally if working within a desktop environment.
    Crucially, this container includes a custom Dockerfile to install the necessary drivers and modules for proper PHP Data Objects (PDO) functionality.
  • mariaDB
    This container serves as another backbone of our infrastructure—the database engine. MariaDB will store the sample mock data tables that the web application queries.
  • phpmyadmin
    While not strictly mandatory for application functionality, it provides a highly useful web-based administration interface to manage and inspect the MariaDB instance.

    This container operates on port 8080 by default.

The entire environment can be initialized using the command: docker-compose up -d --build.

3.2 PHP-Apache Configuration

The PHP-Apache container undergoes two minor modifications. One is the enabling/disabling mechanism for mod_security, which is covered in section 3.5.1 of this document.

Additionally, native PHP runtime error displaying has been disabled within the php.ini configuration file to simulate real-world conditions.

3.3 MariaDB Configuration

For the application to function correctly, a series of standalone, non-relational tables were created. These tables inside the database are used by different application modules to ensure sample data exists for user interaction.

The only three tables featuring relational connections are ordenes (orders), clientes (customers), and productos (products), which adhere to the following schema:

Following this setup, I populated the tables with realistic sample data.

Note: It is critical to emphasize that in a secure environment, the usuarios (users) table must store passwords as a cryptographic hash, never as plain text. However, due to the educational nature of this laboratory, I decided to store them in plain text to make the exploitation and data dumping phase more visually interesting for students.
To reiterate: this application is intentionally vulnerable; this architectural design must NEVER be replicated in production environments.

Furthermore, as observed in the configuration files, the entire web application connects using the database root account. This represents a severe security anti-pattern and a critical vulnerability on its own. In a real-world scenario, any successful injection exploit would lead to a total compromise of the entire database server.
To implement proper security engineering, we should create unique service accounts for each distinct webpage. Each account should only have access to strictly required tables with strictly required privileges, enforcing the Principle of Least Privilege.
This ensures that if one specific page is compromised via an injection flaw, the remaining modules and databases stay isolated and unaffected.
Given the didactic purpose of this application, I deliberately chose to bypass this isolation rule by using the root account globally. This allows the student to explore the full spectrum of advanced post-exploitation possibilities.

The correct procedure to remediate this access control flaw via phpMyAdmin is as follows:

  • Access the target database, navigate to the User Accounts (Privileges) section, and click Add user account.
  • Create the new service account. At this stage, do not assign any global privileges.
  • Once created, navigate to the specific table permissions and grant only the SELECT privilege for the required table.

By following this procedure across separate application modules, we enforce the Principle of Least Privilege and significantly minimize the blast radius of a potential compromise, even if the source code contains a injection flaw.

3.4 Web Applicatio

First, we define the common core files of the application: db.php, styles.css, and functions.php, followed by building the main index.php landing page.

index.php

This file utilizes standard HTML structure, defining the different exploitation modules of the laboratory as container blocks and providing links to access them.

Each container block provides an illustrative image and introductory context regarding that specific attack vector.

db.php

This file defines the centralized database connection instance reused by all backend scripts.

As noted previously, this connection definition contains a flaw, as it openly violates the principle of least privilege by defaulting to the root administrative account.

A secure remediation for this structure involves wrapping the connections into modular functions, specifying distinct low-privileged credentials depending on the application context calling the database.

functions.php

This file handles the global functional logic of the application. These functions will be dissected individually as they appear across the different modules.

style.css

This file defines the global cascading style sheets utilized to format the web application's layout.

3.4.1 SQL Injection (SQLi)

Login

This module simulates a standard user authentication portal, allowing students to practice authentication bypass methodologies using various SQL payloads.

The interface displays the underlying SQL query running in real time at the top, with the login form rendered in the center.

This section is driven by two PHP scripts: login.php, which renders the initial form, and authenticate.php, which processes the credentials.

login.php

A clean HTML form utilizing the HTTP POST method to transmit the username and password parameters to the authentication backend.

authenticate.php

This script handles the authentication result. Visually, it matches the login interface but renders conditional text based on the database response.
Mechanically, it imports db.php and functions.php, invokes the consulta_login() function, and stores the resulting array in the $consulta variable.

Inspecting functions.php reveals the definition of consulta_login(), which contains the raw vulnerability.

The flaw resides in how user data is appended to the SQL query. The code directly interpolates raw PHP variables into the query string before compiling it. As a result, the database engine does not treat the user input as plain text, but as executable SQL commands, creating a classic SQLi flaw.

When the query executes, if the username and password match a record, it returns the associated user row; otherwise, it returns an empty set. The backend merely evaluates if the returned dataset contains rows to grant or deny access.

Vulnerability Remediation

To fix this flaw, we must implement Parameterized Queries (Prepared Statements). This process completely decouples the SQL query structure from the user data, ensuring that the input parameters are strictly parsed as string literals rather than executable commands.


With this implementation, user inputs are safely bound by the driver database protocol as plain text strings. Because the SQL command structure is pre-compiled on the engine before injecting the parameters, execution logic manipulation is entirely prevented.

Store

This section simulates an e-commerce search engine that displays matching catalog items based on user criteria.

The logic is contained within a single file, store.php. It utilizes an HTML form that issues an HTTP GET request to itself, passing the search query through an unvalidated database function to retrieve and render the results on screen.

The root cause matches the authentication flaw closely.

Once again, the developer failed to use prepared statements. However, because this specific page prints database records directly to the screen, users can leverage this module to learn data exfiltration techniques using UNION operators.

Vulnerability Remediation

As established, remediation requires migrating the dynamic query to a secure prepared statement to bind user filters safely.

Flag Validators

The laboratory features 4 identically designed pages. Each presents a form prompting for a "Flag" and queries the database via an unvalidated string to check if the input matches a valid record.

These modules use an HTML form passing the flag parameter via an HTTP GET request to its respective validation script.

The verification is processed using an unvalidated query structure.

The vulnerability is identical: the omission of prepared statements causes the SQL engine to interpret user-supplied characters as executable syntax.

Vulnerability Remediation
The definitive fix requires updating the backend logic to execute parameterized database bindings.

The core difference across these 4 validation sections lies entirely in how the application handles and renders the database engine's response and error states:

Conditional Responses (Boolean-Based)

The application evaluates whether the flag exists in the database. It prints one specific visual message if the record is found and a different message if it is absent. Both states are explicitly readable on the interface.


While displaying binary success/failure status is necessary for functional search workflows, it is recommended to minimize verbose application status messages wherever possible. However, this design pattern is not classified as an independent security vulnerability.

Visible Errors (Error-Based)

In this scenario, the application suppresses functional success indicators but outputs internal system error exceptions directly to the user interface if a query fails.

The primary security failure here is that the application handles exceptions by leaking raw database engine logs directly into the web markup.

This is an active vulnerability. Disclosing internal stack traces or database errors to end-users is a severe misconfiguration. It provides threat actors with structural metadata regarding the database architecture, table attributes, and syntax dialects. This information must be restricted exclusively to internal development and administrative logging utilities.

Conditional Errors (Blind Error-Based)

In this variation, the application suppresses detailed error messages. If a database error occurs, it merely prints a generic alert stating that an execution error occurred, without disclosing structural details.

Because the underlying query remains vulnerable to injection, an attacker can intentionally force specific database execution exceptions (e.g., division by zero) to infer data states based on whether the generic error condition is triggered or skipped.

Non-Reflective/Suppressed (Time-Based)

This module represents industry best practice regarding database exception handling: gracefully catching runtime errors internally without rendering any visible indicator or message updates to the client side.

Even though the user cannot perceive any visual modifications or error messages on the screen, the underlying channel remains vulnerable to inference attacks using Time-Based Blind SQLi payloads. This proves that peripheral defensive logic only complicates the exploitation phase; the only definitive method to secure an application against injection flaws is server-side input parameter binding via prepared statements.

Any other defensive measure merely acts as a hurdle rather than a fix.

Second-Order SQLi

Second-Order SQLi occurs when user-supplied input is securely stored inside the database initially (e.g., during registration or profile setup), but is later fetched and executed inside a vulnerable, unparameterized query within a completely separate application module.

Consequently, this exploit requires a two-step sequence: an initial module to plant the payload into storage, and a secondary module that reads and executes the stored string.

ordenInsert.php


Through this interface, users can generate a service order by inputting an order name and selecting a customer and product from dropdown menus.

The form generation code uses secure queries to extract active reference keys from the database to build the selection fields safely.

The form parameters are then handled by a secure, parameterized INSERT query that commits the records into the ordenes table.


While this specific insertion query is immune to immediate SQLi, it is worth noting that the code fails to pass the string through functions like htmlspecialchars(). Doing so is a defensive best practice to filter input structures across HTML, PHP, and SQL boundaries. While not directly exploitable at this stage, the code leaves room for down-line security improvements.

Vulnerability Remediation

To reinforce ordenInsert.php, the incoming form data should be validated and escaped. However, it is vital to note that this merely sanitizes the storage layer; if a subsequent system routine queries this data insecurely via string concatenation, injection remains entirely possible.

verOrden.php

This secondary script contains the active execution flaw. The page aggregates and displays detailed service order metrics, cross-referencing customer IDs and product codes.

The analytical query responsible for rendering these metrics is highly vulnerable.

As illustrated, the developer relied on inline string concatenation, assuming that because the variables are fetched directly from internal database rows rather than direct HTTP input, they are inherently safe. Because an attacker can inject malicious strings into those rows during the ordering step, the reporting page executes the payload seamlessly upon retrieval.

Vulnerability Remediation

The definitive resolution requires updating the secondary reporting script to process internal database parameters using standard parameterized prepared statements.

This forces the database engine to treat retrieved parameters strictly as plain text data, rendering the stored exploit string inert.

3.4.2 Cross-Site Scripting (XSS)

XSS is a vulnerability arising from a failure to sanitize user inputs before rendering them back into the application markup. This allows an attacker to inject malicious client-side JavaScript or HTML code that the victim's browser executes natively, enabling session hijacking, defacement, or client-side context manipulation.

The two primary categories of XSS are Reflected XSS and Stored XSS.

Reflected XSS

In a Reflected XSS scenario, the malicious payload is part of the request sent to the server (often embedded within URL parameters) and is immediately echoed back in the server's response. Because it does not persist in a database, the attacker must use social engineering to trick the victim into executing the request. Let's look at an example:

This search module is vulnerable to XSS. If a script block is supplied within the query parameter, it fires automatically.

The vulnerability stems from a total lack of output encoding before rendering user parameters onto the DOM.

The script prints raw user data directly into the HTML body, prompting the browser to parse and execute the script tags natively.

Because this form transmits parameters via an HTTP GET request, executing the exploit merely requires sending the weaponized link to a target user. When the victim interacts with the trusted URL, the embedded JavaScript executes seamlessly within their session context. (If the form utilized POST requests, the delivery vector would require hosting a malicious intermediate script to force-submit the payload).

Vulnerability Remediation
To remediate Reflected XSS, the application must process user data through output encoding functions such as htmlspecialchars() before rendering it onto the page. This translates dangerous characters like < and > into safe HTML entities (&lt; and &gt;), rendering scripts harmless.


Stored XSS

Stored XSS constitutes a much higher security risk. The malicious payload is saved permanently in the application database rather than being immediately reflected. As a result, the attacker does not need to distribute malicious links; any user who naturally browses to the affected page executes the payload automatically.

In this scenario, we inspect a customer support ticketing form designed to send messages directly to an administrative portal.

Analyzing the backend code confirms that incoming strings are committed directly to the database without undergoing filtering or verification.


This permits arbitrary script elements to be saved in long-term storage.

Subsequently, when an administrator authenticates to review the pending support queue on their dedicated dashboard:

The interface renders the ticketing data without validating or escaping the strings retrieved from the database.

Consequently, the administrator's browser executes the stored payload automatically within their high-privileged context upon opening the inbox view.

Vulnerability Remediation
Resolving Stored XSS requires enforcing comprehensive output encoding at the presentation layer when rendering data, along with contextual input validation before committing strings to database storage.


Implementing these encoding layers effectively prevents the browser from interpreting user data as active HTML elements.

3.5 Prompt Injection

Exploitation methodologies targeting Large Language Models (LLMs) are structurally unique. However, the conceptual root cause remains identical to classic injection flaws: a lack of isolation between control instructions and untrusted user-supplied data, allowing the model to interpret data inputs as administrative commands.
For this laboratory deployment, I selected DeepSeek-R1-1.5B due to its low hardware resource footprint and its susceptibility to instructional manipulation vectors.

The deployment relies on Ollama as the local model engine and Open WebUI as the web interface. The configuration process is straightforward:

First, I install Ollama utilizing the official distribution script.

Next, I download the target DeepSeek weight profile and adjust the network host bindings.


Finally, I initialize the frontend using the official Open WebUI Docker container instance.

The environment now hosts a local, responsive DeepSeek model interface ready for prompt injection security analysis.

3.6 Defensive Controls and Mitigations

While the gold standard for securing web systems relies on source-code remediation and context-aware data sanitization, system administrators often operate in environments managing large codebases built by distributed teams. When direct code modifications are unfeasible, implementing an inline perimeter defense layer is vital to inspect, block, and log exploitation attempts.

3.6.1 OWASP ModSecurity

ModSecurity is an open-source Web Application Firewall (WAF) deployed natively as an Apache module. It evaluates inbound HTTP traffic against a defined rule framework—specifically the OWASP Core Rule Set (CRS)—to identify and intercept common web attack patterns, including SQLi and XSS payloads.

It is a well-established, highly effective, and accessible defensive solution for web server hardening.

The module installation is handled through the system package manager:


Once installed, the core rule definitions must be activated and configured.

First, we generate the active operational configuration profile from the template.

Next, we enable the WAF processing engine by updating the SecRuleEngine directive to On within the configuration file.

If we attempt to replicate our previous SQL injection vectors with the firewall active:

The WAF detects the anomalous payload and drops the connection immediately, returning an HTTP status code.

Furthermore, a detailed forensic audit trail of the block event is written to the centralized log repository located at /var/log/apache2/modsec_audit.log.

This log stores deep context regarding the suspicious connection, including origin IP mapping, full HTTP headers, URI strings, and the specific rule signature triggered.
It is important to emphasize that WAF architectures can often be bypassed using obfuscation and evasion payloads; they are not silver bullets. The only definitive method to secure an application against injection flaws is fixing the underlying source code. However, a WAF serves as an excellent defense-in-depth tool, providing an extra layer of visibility and protection against unforeseen zero-day exposures or legacy third-party system components.

4. Conclusions

Throughout this project, I successfully developed a functional, intentionally vulnerable training application capable of safely demonstrating two of the most critical security flaws in modern web development: SQL Injection and Cross-Site Scripting. Both flaws share a common root cause: the failure to sanitize user data before parsing it within execution blocks or rendering it into browser documents.

Furthermore, this study highlights the coding habits that lead to these vulnerabilities, while providing concrete code fixes, defense-in-depth strategies, and industry best practices to prevent these risks.

The project highlights the necessity of the Principle of Least Privilege at the database layer to dramatically restrict data exposure in the event of an application layer compromise.

Additionally, we evaluated practical server hardening techniques using Apache security extensions, demonstrating how tools like ModSecurity function as effective perimeter defensive layers.

Ultimately, this project delivers an educational, containerized laboratory that simplifies complex security concepts into visual, accessible scenarios. It serves as a tool for security awareness, illustrating the real-world impact of insecure coding practices and warning against assuming security without explicit verification—especially in applications driven by user-supplied input.

Bibliography

PortSwigger SQL Injection
PortSwigger Cross-Site Scripting
OWASP SQL Injection
OWASP Cross-Site Scripting
Radware SQL Injection Fundamentals
Halfond, W. G. J., Viegas, J., & Orso, A. (2006). A classification of SQL-injection attacks and countermeasures. Proceedings of the IEEE International Symposium on Secure Software Engineering.
Cisco Talos Security Risk Evaluation of DeepSeek-R1 and Frontier Reasoning Models

Appendices

Appendix – Exploitation Guide

In this initial document, I focused on documenting the system architecture, development timeline, intentional vulnerabilities, and their direct source-code remediations.
However, because analyzing the identification, exploitation, and business impact mechanics is equally vital, I separated these tasks to prevent the technical report from becoming over-encumbered. Consequently, this main document functions as the core development report, while the companion Exploitation Manual acts as a theoretical thesis and hands-on guide covering attack execution within the laboratory environment.