September 20, 2026
PortSwigger: Bypassing Authentication with SQL Injection (Lab #2)
Following up on my first walkthrough on retrieving hidden data, I tackled PortSwigger’s SQL injection vulnerability allowing login bypass.
By Sudeepth P
3 min read
Authentication bypasses are among the most dangerous outcomes of SQL injection. When login logic concatenates unsanitized user credentials directly into a database query, you can bypass the password check entirely and take over arbitrary accounts — including the administrator.
Here is how the flaw works, how I exploited it, and how it should be remediated.
The Underlying Vulnerability
When a user submits credentials on a login page, the backend application verifies identity against the database using a query structured like this:
SELECT * FROM users WHERE username = 'USER_INPUT' AND password = 'USER_INPUT'SELECT * FROM users WHERE username = 'USER_INPUT' AND password = 'USER_INPUT'- Intended Logic: The query returns a row only if the entered
usernamematches an existing account and the enteredpasswordmatches the stored hash or string. If a row returns, the session authenticates; if no rows return, authentication fails. - The Flaw: If the
usernamefield accepts raw user input without parameterization, we can inject characters that break out of the string literal and alter the logical structure of the query.
Crafting the Payload
Our goal is to log in specifically as the administrator user without knowing their password.
I injected the following into the username field:
administrator'--administrator'--Any arbitrary text can be supplied for the password (e.g., test or even left blank).
When the application concatenates this input into the backend query, it transforms into:
SELECT * FROM users WHERE username = 'administrator'--' AND password = 'any_password'SELECT * FROM users WHERE username = 'administrator'--' AND password = 'any_password'Why this succeeds:
- ' closes the string literal for the
usernamevalue. - -- initiates a SQL comment sequence. The database treats everything following -- as a comment, completely stripping out
' AND password = 'any_password'. - The executed query is effectively reduced to:
SELECT * FROM users WHERE username = 'administrator'SELECT * FROM users WHERE username = 'administrator'- The database finds the record for
administratorand returns it. Because a valid user record is returned, the backend application assumes authentication succeeded and grants an administrative session.
Exploitation Steps
Method 1: Directly via the Browser
- Navigate to the login endpoint (
/login). - In the Username field, input:
administrator'--administrator'--
- In the Password field, enter any random character sequence (e.g.,
12345). - Click Log in. The application will authenticate you immediately as
administrator, and the lab will mark as solved.
Method 2: Intercepting via Burp Suite
- Turn intercept on in Burp Suite Proxy (
Proxy->Intercept is on). - Submit a login attempt through the web application.
- Catch the outgoing
POST /loginrequest:
POST /login HTTP/1.1 Host: <TARGET-ID>.web-security-academy.net Content-Type: application/x-www-form-urlencoded Content-Length: ... csrf=...&username=test&password=testPOST /login HTTP/1.1 Host: <TARGET-ID>.web-security-academy.net Content-Type: application/x-www-form-urlencoded Content-Length: ... csrf=...&username=test&password=test
csrf=...&username=administrator'--&password=testcsrf=...&username=administrator'--&password=test(Note: Burp Suite URL-encodes the single quote as %27 in form-encoded requests).
- Forward the request 2 times . In the response, look for an HTTP
302 Foundredirect setting an authenticated session cookie:
HTTP/1.1 302 Found Location: /my-account?id=administrator Set-Cookie: session=...; Path=/; Secure; HttpOnlyHTTP/1.1 302 Found Location: /my-account?id=administrator Set-Cookie: session=...; Path=/; Secure; HttpOnly- Follow the redirection in the browser. You are logged into the administrator portal.
Recommended Remediation
Authentication endpoints should never concatenate strings into SQL queries. The standard defense is utilizing Parameterized Queries (Prepared Statements):
// Example in Java with Prepared Statements
String sql = "SELECT id, username, password_hash FROM users WHERE username = ?";
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setString(1, inputUsername);
ResultSet rs = stmt.executeQuery();
if (rs.next()) {
String storedHash = rs.getString("password_hash");
// Verify password against stored hash using a secure hashing algorithm (e.g., Argon2, bcrypt)
if (BCrypt.checkpw(inputPassword, storedHash)) {
// Authenticate session
}
}// Example in Java with Prepared Statements
String sql = "SELECT id, username, password_hash FROM users WHERE username = ?";
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setString(1, inputUsername);
ResultSet rs = stmt.executeQuery();
if (rs.next()) {
String storedHash = rs.getString("password_hash");
// Verify password against stored hash using a secure hashing algorithm (e.g., Argon2, bcrypt)
if (BCrypt.checkpw(inputPassword, storedHash)) {
// Authenticate session
}
}- By decoupling query compilation from data binding, the database treats
administrator'--as the literal username being queried rather than executable SQL syntax. - Passwords should never be compared in plaintext within SQL queries; they should be retrieved and verified against salted cryptographic hashes using standard libraries.