Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Exploiting our Application

Prediction Exercise

Before trying any payload, answer this to yourself.

If I type test as the username and password123 as the password, what would the query look like based off of app.py’s vulnerable line?

Take a look back at the line: f"SELECT id, username FROM users WHERE username = '{username}' AND password = '{password}'"

With test and password123 it would become:

SELECT id, username FROM users WHERE username = 'test' AND password = 'password123'

This matches! The single quotes are added by our code, and our input goes inside of them. This is the key.

Exploit 1: Comment out the rest of the query (--)

The SQL comment -- will tell the database to ignore everything after it on that line.

  1. Go to the login page.
  2. For Username, type: admin' --
  3. For Password, type: anything (it doesn’t matter, it will be commented out!)
  4. Click Login

Observe

Look at the query box. It should look something like this:

SELECT id, username FROM users WHERE username = 'admin' -- ' AND password = 'anything'

See what happened? Our input injected admin' which closed the username’s quote, and -- commented out AND password = '...'. The password check has been completely removed! Because of this, we are logged in as admin without knowing the password.

What happened (Breakdown)

  • Original structure: WHERE username = '...input...' AND password = '...input...'
  • We made it: WHERE username = 'admin' followed by a comment, so the AND password = ... is ignored by the database.

Exploit 2: Make the condition always true (OR '1'='1')

This is one of the most famous payloads. '1'='1' is always true in SQL.

  1. Clear the form (refresh the page)
  2. For Username, type: ' OR '1'='1' --
  3. For Password, type: anything
  4. Click Login

Observe

Your query should look similar to this:

SELECT id, username FROM users WHERE username = '' OR '1'='1' -- ' AND password = 'anything'

The WHERE clause is now (username = '') OR ('1'='1'). '1'='1' is always true, so this condition is true for at least the first row that it finds. Depending on how the database returns it, this will often log us in (in this case it will authenticate as a user).

What happened (Breakdown)

  • We closed the quotes with ', added OR '1'='1' which makes the logic always evaluate to true.
  • We commented out the rest with -- to ignore the password check entirely.

Exercise Time

Before moving onto the fixes, try to answer these questions. Do not look up the answers, reason them out by looking at the query box!

  1. Why did admin' -- work, even though we put garbage into the password field?
  2. Why does '1'='1' make the login succeed?
  3. If I change the payload to ' OR '1'='0' --, would it succeed or fail? Try it and see! (Predict first, then test.)

Checkpoint 4

  • I was able to log in as admin without the password using admin' --
  • I was able to bypass the login using ' OR '1'='1' --
  • I have looked at the query box for both payloads and can explain, in my own words, why the query changed
  • I have attempted the prediction exercise above

Note

Take a moment to appreciate what we just did. This is the bug in action. The fix is to make it so that no matter what somebody types, it can never change the structure of the SQL query. This is exactly what parameterized queries do.