Skip to main content

Lesson Learned?

Executive Summary

This report details the penetration testing of a web application intentionally designed to teach secure SQL injection practices. The application's login mechanism was vulnerable to both username enumeration and SQL injection. A common, but potentially destructive, SQL injection payload (OR 1=1) was initially tested, highlighting its risks. A safer and more precise SQL injection was then used to successfully bypass authentication.

1. Information Gathering and Reconnaissance

The target application presents a login form. Initial interaction suggests a potential SQL injection vulnerability due to the detailed error messages. The key observation is the difference in error messages based on input:

  • Incorrect Username and Password: "Invalid username and password."
  • Correct Username, Incorrect Password: "Invalid password."

This difference in response reveals a username enumeration vulnerability. The application inadvertently discloses whether a given username exists in the database.

2. Vulnerability Analysis and Exploitation

2.1 Username Enumeration (Proof of Concept)

The username enumeration vulnerability can be exploited using a tool like hydra. This allows us to systematically test a list of potential usernames and identify valid ones.

hydra -L /usr/share/wordlists/seclists/Usernames/xato-net-10-million-usernames.txt -p testing 10.10.243.105 http-post-form "/:username=^USER^&password=^PASS^:Invalid username and password."
  • -L: Specifies a file containing a list of usernames. /usr/share/wordlists/seclists/Usernames/xato-net-10-million-usernames.txt is a commonly used wordlist.
  • -p testing: Uses a static password ("testing") for the brute-force attempt. We are focusing on username enumeration, not password cracking at this stage.
  • http-post-form: Specifies the HTTP method (POST) and the form data.
  • /:username=^USER^&password=^PASS^: Defines the form parameters. ^USER^ and ^PASS^ are placeholders that hydra will replace with values from the username list and the specified password.
  • Invalid username and password.: The failure string, used to detect which request did not match a username.

This command reveals several valid usernames, including "martin". Attempting to log in with "martin" and an incorrect password results in the "Invalid password." message, confirming the username's validity.

2.2 SQL Injection (Initial Attempt - Destructive)

As an initial test, and to demonstrate the risks, a common but dangerous SQL injection payload was attempted:

' OR 1=1 -- -

This payload, when injected into the username field, modifies the underlying SQL query. The application's error message after this injection is crucial:

"Oops! It looks like you injected an OR 1=1 or similar into the username field. This wouldn't have bypassed the login because every row in the users table was returned, and the login check only proceeds if one row matches the query. However, your injection also made it into a DELETE statement, and now the flag is gone."

Explanation of the Destructive Behavior:

  • OR 1=1: This condition is always true. In a SELECT statement used for authentication, this would typically return all rows from the users table. Many login implementations check if exactly one row is returned (indicating a successful username/password match). Therefore, OR 1=1 often fails to bypass authentication directly.
  • Unintended DELETE Statement: The application's vulnerability lies in how it handles the injected input in other SQL statements. The error message explicitly states that the injection triggered a DELETE statement. Because OR 1=1 is always true, the DELETE statement likely had a WHERE clause that evaluated to true for all rows, effectively deleting the flag (and potentially other data). This is a critical lesson in the dangers of unchecked user input.
  • Comment: -- - comments out the rest of the SQL statement, preventing syntax errors.

2.3 SQL Injection (Safe and Successful)

A more controlled and safer SQL injection payload is used, leveraging the enumerated username "martin":

martin' AND '1'='1'-- -

Explanation:

  • martin': We start with a valid username. This is crucial because we want to manipulate the query's logic, not just return all rows. The single quote closes the username string in the original query.
  • AND '1'='1': This condition is always true, similar to OR 1=1, but it's appended with AND. This is significantly less likely to cause unintended consequences in other parts of the application. It maintains the original query's logic (checking for the username "martin") while also adding a trivially true condition.
  • -- -: The SQL comment, as before, prevents syntax errors.

This injection likely modifies the original query to something like:

SELECT * FROM users WHERE username = 'martin' AND '1'='1'-- -' AND password = '...'

Because we've provided a valid username and a true condition ('1'='1'), and we have commented out the password check, the query returns the "martin" user's row, bypassing the authentication. This approach avoids the risk of affecting other database operations.

3. Successful Authentication Bypass and Flag Retrieval

The safe SQL injection successfully bypasses the login, granting access to the application and revealing the flag. The application then presents a final message reinforcing the lesson:

"Well done! You bypassed the login without deleting the flag! ... Using OR 1=1 is risky and should rarely be used in real-world engagements... Consider using AND 1=1 as an alternative, with a valid input (in this case a valid username) to test / confirm SQL injection."