Skip to content

feat: add challenge mode to Error-Based and Union-Based SQL Injection - #708

Open
Mubashir78 wants to merge 3 commits into
SasanLabs:masterfrom
Mubashir78:feat/sql-injection-challenge-mode
Open

feat: add challenge mode to Error-Based and Union-Based SQL Injection#708
Mubashir78 wants to merge 3 commits into
SasanLabs:masterfrom
Mubashir78:feat/sql-injection-challenge-mode

Conversation

@Mubashir78

@Mubashir78 Mubashir78 commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Add @ChallengeCard annotations to all unsecure levels in ErrorBasedSQLInjectionVulnerability and UnionBasedSQLInjectionVulnerability, following the established pattern from BlindSQLInjectionVulnerability.

Changes

ErrorBasedSQLInjectionVulnerability.java

  • Added @ChallengeCard annotations to 4 unsecure levels (Level1-Level4)
  • Each includes challenge text, 2 hints, and payload description/value

UnionBasedSQLInjectionVulnerability.java

  • Added @ChallengeCard annotations to 2 unsecure levels (Level1-Level2)
  • Same structure as above

messages.properties

  • Added 30 new message keys for challenge text, hints, and payloads

Closes #561

Summary by CodeRabbit

  • New Features
    • Added challenge cards for Error-Based SQL Injection levels 1–4.
    • Added challenge cards for Union-Based SQL Injection levels 1–2.
    • Each card includes challenge text, progressive hints, and an example payload for the corresponding level.
  • Localization
    • Added localized (i18n) labels and guidance for the new SQL injection challenge modes, including payload descriptions and examples.

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0e7e3515-bba2-4342-937a-2cb07b522713

📥 Commits

Reviewing files that changed from the base of the PR and between 4bc310b and 7a940f1.

📒 Files selected for processing (3)
  • src/main/java/org/sasanlabs/service/vulnerability/sqlInjection/ErrorBasedSQLInjectionVulnerability.java
  • src/main/java/org/sasanlabs/service/vulnerability/sqlInjection/UnionBasedSQLInjectionVulnerability.java
  • src/main/resources/i18n/messages.properties
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/main/resources/i18n/messages.properties
  • src/main/java/org/sasanlabs/service/vulnerability/sqlInjection/UnionBasedSQLInjectionVulnerability.java
  • src/main/java/org/sasanlabs/service/vulnerability/sqlInjection/ErrorBasedSQLInjectionVulnerability.java

📝 Walkthrough

Walkthrough

Challenge-mode metadata is added to error-based SQL injection levels 1–4 and union-based levels 1–2. Localized challenge text, hints, payload descriptions, and example values are added without changing endpoint logic.

Changes

SQL Injection Challenge Mode

Layer / File(s) Summary
Challenge card endpoint metadata
src/main/java/org/sasanlabs/service/vulnerability/sqlInjection/ErrorBasedSQLInjectionVulnerability.java, src/main/java/org/sasanlabs/service/vulnerability/sqlInjection/UnionBasedSQLInjectionVulnerability.java
Adds ChallengeCard annotations with ordered hints and payload definitions for the supported SQL injection levels.
Challenge card localization
src/main/resources/i18n/messages.properties
Adds message keys for error-based and union-based challenge descriptions, hints, payload descriptions, and example values.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

  • Issue 568: Adds similar ChallengeCard metadata and localization for vulnerability levels.
  • Issue 559: Adds related ChallengeCard annotations and matching localized messages.
  • Issue 565: Adds challenge metadata and i18n entries while preserving endpoint behavior.

Possibly related PRs

Suggested reviewers: preetkaran20

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: adding challenge mode to SQL injection vulnerabilities.
Linked Issues check ✅ Passed The PR adds @ChallengeCard metadata and message keys for the targeted SQLi levels, matching the challenge-mode requirements.
Out of Scope Changes check ✅ Passed The changes stay within challenge-mode annotations and i18n keys for the SQL injection modules.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov-commenter

codecov-commenter commented Jul 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 55.37%. Comparing base (a51ed38) to head (7a940f1).

Additional details and impacted files
@@            Coverage Diff            @@
##             master     #708   +/-   ##
=========================================
  Coverage     55.37%   55.37%           
  Complexity      760      760           
=========================================
  Files           105      105           
  Lines          4229     4229           
  Branches        452      452           
=========================================
  Hits           2342     2342           
  Misses         1683     1683           
  Partials        204      204           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/resources/i18n/messages.properties`:
- Around line 310-314: Align the Level 1 UNION challenge text and payload by
updating UNION_SQL_INJECTION_VULNERABILITY_LEVEL1_PAYLOAD_VALUE to select from a
distinct existing table, while preserving the expected column count and
extraction behavior described by the challenge and hints.
- Around line 291-295: The Level 2 SQL injection payload values must account for
the endpoint-appended closing quote. Update
ERROR_SQL_INJECTION_VULNERABILITY_LEVEL2_PAYLOAD_VALUE and the corresponding
Level 2 UNION payload near the related entries to include a closing quote before
the comment marker and trailing whitespace after --, using H2-compatible syntax
such as ' OR '1'='1' --.
- Around line 297-307: Revise the Level 3 and Level 4 challenge, hint, payload
description, and payload value entries to match the actual endpoint behavior,
where single quotes are stripped before constructing the query. Remove the
currently invalid injection claims and payloads, and use only a verified exploit
for the exact methods; otherwise describe the input as remaining a quoted
literal and adjust the challenge accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f307322a-9125-4493-bd64-7d325fc4fda0

📥 Commits

Reviewing files that changed from the base of the PR and between bad68b1 and fe8328c.

📒 Files selected for processing (3)
  • src/main/java/org/sasanlabs/service/vulnerability/sqlInjection/ErrorBasedSQLInjectionVulnerability.java
  • src/main/java/org/sasanlabs/service/vulnerability/sqlInjection/UnionBasedSQLInjectionVulnerability.java
  • src/main/resources/i18n/messages.properties

Comment thread src/main/resources/i18n/messages.properties Outdated
Comment thread src/main/resources/i18n/messages.properties Outdated
Comment thread src/main/resources/i18n/messages.properties Outdated
@Mubashir78

Copy link
Copy Markdown
Contributor Author

@coderabbitai

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@Mubashir78: How can I help with this PR?

@Mubashir78

Copy link
Copy Markdown
Contributor Author

@coderabbitai Review latest changes pushed on this PR

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

@Mubashir78 I’ll review the latest changes on this PR.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@Mubashir78

Copy link
Copy Markdown
Contributor Author

@coderabbitai you need to review the latest commit, not the commit you have already reviewed.

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== PR commits =="
gh pr view 708 --repo SasanLabs/VulnerableApp --json commits --jq '.commits[] | "\(.oid)\t\(.messageHeadline)"'

echo
echo "== Checked-out head and parent =="
git show -s --format='%H%n%P%n%s' HEAD

echo
echo "== Exact latest-commit diff summary =="
git diff --stat HEAD^ HEAD

echo
echo "== Exact latest-commit diff =="
git diff --find-renames --find-copies --no-ext-diff HEAD^ HEAD

Length of output: 6687


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== SQL injection class outlines =="
ast-grep outline src/main/java/org/sasanlabs/service/vulnerability/sqlInjection/ErrorBasedSQLInjectionVulnerability.java --items all
ast-grep outline src/main/java/org/sasanlabs/service/vulnerability/sqlInjection/UnionBasedSQLInjectionVulnerability.java --items all

echo
echo "== Endpoint query construction and challenge annotations =="
rg -n -C 12 --type java \
  'LEVEL[1-4]|prepareStatement\s*\(|SELECT\s+|replaceAll\s*\(|createStatement\s*\(' \
  src/main/java/org/sasanlabs/service/vulnerability/sqlInjection/ErrorBasedSQLInjectionVulnerability.java \
  src/main/java/org/sasanlabs/service/vulnerability/sqlInjection/UnionBasedSQLInjectionVulnerability.java

echo
echo "== auth_users schema and column references =="
rg -n -i -C 8 \
  '(CREATE\s+TABLE\s+(IF\s+NOT\s+EXISTS\s+)?auth_users\b|INSERT\s+INTO\s+auth_users\b|\bauth_users\b)' \
  src

Length of output: 82546


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Database initialization / data source references =="
rg -n -i -C 6 \
  '(applicationJdbcTemplate|applicationDataSource|jdbc:|schema\.sql|data\.sql|ResourceDatabasePopulator|ScriptUtils|DatabasePopulator)' \
  src/main src/test

echo
echo "== Authentication database script references =="
rg -n -C 5 \
  '(scripts/Authentication/db/(schema|data)\.sql|Authentication/db/(schema|data)\.sql)' \
  src

echo
echo "== Changed properties keys: duplicate and continuation validation =="
python3 - <<'PY'
from collections import Counter
from pathlib import Path

path = Path("src/main/resources/i18n/messages.properties")
lines = path.read_text(encoding="utf-8").splitlines()
keys = []
for number, line in enumerate(lines, 1):
    stripped = line.lstrip()
    if not stripped or stripped.startswith(("#", "!")) or line.endswith("\\"):
        continue
    if "=" in line:
        key = line.split("=", 1)[0].strip()
        keys.append((key, number))
counts = Counter(key for key, _ in keys)
duplicates = [(key, number) for key, number in keys if counts[key] > 1]
print("Duplicate keys:", duplicates if duplicates else "none")
for number in range(292, 321):
    print(f"{number}: {lines[number - 1]!r}")
PY

Length of output: 59854


@Mubashir78 Reviewed the latest commit specifically: 4bc310b7f3790600a9da6a7369865d1fb38d1fa6 (fix: address CodeRabbit review feedback on SQL injection challenge payloads).

No actionable issues found. The revised UNION payloads match the three-column cars result shape and can access auth_users in the same H2 database; the Level 2 payloads retain the required H2 comment trailing space; and the revised Level 3/4 descriptions accurately reflect the single-quote stripping behavior.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

BLIND_SQL_INJECTION_URL_PARAM_WRAPPED_WITH_SINGLE_QUOTE_APPENDED_TO_QUERY=Query param is wrapped around "'" and then appended to the SQL Query hence query can be manipulated.

# Error-Based SQL Injection Challenge Mode
ERROR_SQL_INJECTION_VULNERABILITY_LEVEL1_CHALLENGE=Extract all car information by exploiting error-based SQL injection where the input is appended directly to the query without any wrapping.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these doesn't seems right challenges. I suggest looking at Blind SQL Injection to see how we can really use SQL Injection to extract databases and other details

Add @ChallengeCard annotations to all unsecure levels in
ErrorBasedSQLInjectionVulnerability (4 levels) and
UnionBasedSQLInjectionVulnerability (2 levels), following the
established pattern from BlindSQLInjectionVulnerability.

Add 30 corresponding message keys to messages.properties for
challenge text, hints, and payloads for each level.

Closes SasanLabs#561
…yloads

- Level 2 payloads: add closing quote and trailing space for H2 comment syntax
- Level 3/4 challenge text: accurately describe that replaceAll single-quote stripping prevents standard injection
- UNION Level 1/2 payloads: select from auth_users instead of cars to extract data from a distinct table
…rom auth_users

- Error-based L1/L2: extract admin_sqli password via type conversion errors
- Error-based L3/L4: analyze effectiveness of single-quote stripping
- Union-based L1/L2: extract credentials from auth_users table
@Mubashir78
Mubashir78 force-pushed the feat/sql-injection-challenge-mode branch from 4bc310b to 7a940f1 Compare July 28, 2026 15:46
@Mubashir78

Mubashir78 commented Jul 28, 2026

Copy link
Copy Markdown
Contributor Author
  • Updated the Error-Based and Union-Based SQL Injection challenges to ask for real data instead of just Extract all car information.
  • Challenges now target the admin_sqli password in auth_users, matching the approach taken by the existing Blind SQL Injection challenges.
  • Levels 3 and 4 now describe why the single-quote stripping makes standard injection impractical and focus on analyzing the remaining insecure pattern.

ERROR_SQL_INJECTION_VULNERABILITY_LEVEL3_HINT1=The application removes all single quote characters from the input using replaceAll before building the query.
ERROR_SQL_INJECTION_VULNERABILITY_LEVEL3_HINT2=Although single quotes are stripped, using PreparedStatement with concatenation is the real issue. Without parameterized binding, other injection vectors may still be exploitable.
ERROR_SQL_INJECTION_VULNERABILITY_LEVEL3_PAYLOAD_DESCRIPTION=The single-quote stripping prevents standard injection but the concatenation pattern remains insecure.
ERROR_SQL_INJECTION_VULNERABILITY_LEVEL3_PAYLOAD_VALUE=1 OR 1=1 --

@preetkaran20 preetkaran20 Jul 29, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not have something similar as challenge and payload for this level too as level 1 and level 2?

ERROR_SQL_INJECTION_VULNERABILITY_LEVEL4_HINT1=A PreparedStatement object is created, but the query string is built by concatenation with user input rather than using parameterized binding.
ERROR_SQL_INJECTION_VULNERABILITY_LEVEL4_HINT2=Single quotes are stripped from input before concatenation. However, the PreparedStatement offers zero protection because the injection happens before the query is prepared, not through parameterized placeholders.
ERROR_SQL_INJECTION_VULNERABILITY_LEVEL4_PAYLOAD_DESCRIPTION=The misused PreparedStatement provides no protection since concatenation happens before preparation.
ERROR_SQL_INJECTION_VULNERABILITY_LEVEL4_PAYLOAD_VALUE=1 OR 1=1 --

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above one. this challenge should also be related to retrieving some data from other tables.

ERROR_SQL_INJECTION_VULNERABILITY_LEVEL1_PAYLOAD_DESCRIPTION=Error-based SQL injection that forces the database to display admin_sqli's password through a type conversion error.
ERROR_SQL_INJECTION_VULNERABILITY_LEVEL1_PAYLOAD_VALUE=1 AND CAST((SELECT password FROM auth_users WHERE username='admin_sqli') AS int)=1

ERROR_SQL_INJECTION_VULNERABILITY_LEVEL2_CHALLENGE=The parameter is now wrapped in single quotes. Use the same error-based technique to extract the admin_sqli password from the auth_users table.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BLIND_SQL_INJECTION_URL_PARAM_WRAPPED_WITH_SINGLE_QUOTE_APPENDED_TO_QUERY=Query param is wrapped around "'" and then appended to the SQL Query hence query can be manipulated.

# Error-Based SQL Injection Challenge Mode
ERROR_SQL_INJECTION_VULNERABILITY_LEVEL1_CHALLENGE=Using only the error messages returned by the database, discover the password stored for admin_sqli in the auth_users table. The application never displays table data directly - only errors.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ERROR_SQL_INJECTION_VULNERABILITY_LEVEL4_PAYLOAD_VALUE=1 OR 1=1 --

# Union-Based SQL Injection Challenge Mode
UNION_SQL_INJECTION_VULNERABILITY_LEVEL1_CHALLENGE=Using a UNION-based injection, extract the username and password for admin_sqli from the auth_users table. The input is appended directly with no wrapping.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should not use same challenge for each level. please think of something else. you can start the app and access the database and write the challenges. Accessing ways for database: https://github.com/SasanLabs/VulnerableApp/tree/master#connecting-to-embedded-h2-database

@pereiravp

pereiravp commented Aug 15, 2026

Copy link
Copy Markdown
Member

Hey @Mubashir78, was also working on #561 and only saw this after. Sorry for the overlap, should have checked open PRs first.

Ran your payloads against a live instance before deciding what to do. Level 1 works well and leaks the real password through the CAST error, nice technique, better than what I had. The other five don't reproduce for me though.

Level 2 (' AND CAST(...)=1 -- ) fails because id='' breaks the INT conversion before the AND even runs.

Level 3 and 4 (1 OR 1=1 --) give the same generic conversion error as any bad input, quotes stripped or not.

Union Level 1 (1 UNION SELECT...) doesn't work because id=1 also matches the real Audi row, and since it only reads the first result, the union row never surfaces. Needs a nonexistent id like -1.

Union Level 2 hits the same id='' issue as Level 2, and since UnionBasedSQLInjectionVulnerability isn't wrapped in a try/catch it comes back as a raw 500.

Opened #761 with different payloads for the same 6 levels, verified end to end. Couldn't find a real bypass for levels 3/4 at all, tried quote variants, backslash, unicode look-alikes, dollar quoting, so I built those around the verbose error leaking the table and engine instead.

Not trying to step on this, just want whichever one gets merged to actually work. Happy to fold your Level 1 idea into either PR.

pereiravp added a commit to pereiravp/VulnerableApp that referenced this pull request Aug 16, 2026
Addresses @preetkaran20's review on SasanLabs#761:
- Error-Based levels 1-2 now target extracting admin_sqli's real
  password from auth_users via CAST-based error exfiltration, instead
  of a boolean OR 1=1 tautology - matches the technique from SasanLabs#708's
  Level 1 (independently confirmed working) and is a better fit for
  what "Error-Based" is meant to teach.
- Error-Based levels 3-4 keep the verbose-error-disclosure angle (full
  data access genuinely isn't reachable through this INT-typed,
  quote-stripped id parameter - verified again against the redesigned
  levels 1-2 payloads too) but are now framed as a goal to reach
  (identify the database engine) rather than a description of the
  mechanism.
- Union-Based levels 1-2 now target the same specific admin_sqli
  record via UNION SELECT against auth_users, rather than a generic
  row from an unrelated table.
- Every challenge is now self-contained: no level references another
  level's filtering by name, and quote/mechanism details that were in
  the challenge text moved into the hints instead.

All six payloads re-verified end-to-end against a running instance.
preetkaran20 pushed a commit that referenced this pull request Aug 16, 2026
…#761)

* feat: add Challenge mode to Error-Based and Union-Based SQL Injection (#561)

Completes the remaining two SQL injection classes referenced in #561 -
Blind SQL Injection already has Challenge mode from a prior PR. Follows
that PR's precedent of only annotating UNSECURE levels, keeping all
three SQL injection modules consistent with each other.

Error-Based levels 1-2 and Union-Based levels 1-2 use classic boolean
tautology and UNION SELECT bypasses, verified end-to-end against a
running instance (Union-Based leaks a real row from the unrelated
"users" table into the car response). Error-Based levels 3-4 strip
every single quote from the input and compare it against a strictly
INT-typed column, which closes off actual data access - verified this
holds against quote variants, backslash escaping, and dollar-quoting,
not just the literal apostrophe. Their challenge instead targets the
verbose SQL error the app relays back, which leaks the table name,
column layout, and database engine - a real CWE-209 information
disclosure distinct from full data exfiltration, and an honest
depiction of what those two levels actually expose.

* fix: redesign SQL injection challenges per maintainer review feedback

Addresses @preetkaran20's review on #761:
- Error-Based levels 1-2 now target extracting admin_sqli's real
  password from auth_users via CAST-based error exfiltration, instead
  of a boolean OR 1=1 tautology - matches the technique from #708's
  Level 1 (independently confirmed working) and is a better fit for
  what "Error-Based" is meant to teach.
- Error-Based levels 3-4 keep the verbose-error-disclosure angle (full
  data access genuinely isn't reachable through this INT-typed,
  quote-stripped id parameter - verified again against the redesigned
  levels 1-2 payloads too) but are now framed as a goal to reach
  (identify the database engine) rather than a description of the
  mechanism.
- Union-Based levels 1-2 now target the same specific admin_sqli
  record via UNION SELECT against auth_users, rather than a generic
  row from an unrelated table.
- Every challenge is now self-contained: no level references another
  level's filtering by name, and quote/mechanism details that were in
  the challenge text moved into the hints instead.

All six payloads re-verified end-to-end against a running instance.

* fix: point Union-Based challenges at idor_users instead of auth_users

Error-Based already targets auth_users for admin_sqli's password, so
Union-Based now targets a different table (idor_users) to avoid
teaching the same lesson twice. Leaks the ADMIN role's username and
salary instead. Verified against a running instance.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Challenge mode to sql injection

4 participants