Skip to content

Scenario 2: SQL Injection & Reflected XSS ​

FieldValue
Internal ID06
TypeOffensive (attacker, from the browser)
DifficultyMedium (level 2); lab time limit 45 minutes
Tasks5: four auto-scored milestones and one flag task, total 350 points
Lab surfacedvwa: the right-hand pane is the embedded DVWA browser (DvwaView.tsx)
Scored onBrowser (DVWA proxy signals); Kali history and files as a fallback
Guidecyberrange/portal/public/scenarios/scenario_02_web_application_attack_sql_injection.md
ExplainerScenario 2: SQL Injection & Reflected XSS1:09

Objectives ​

The student attacks DVWA (Damn Vulnerable Web Application), running at security level Low, entirely from the browser through the portal's DVWA proxy, shown as an embedded pane next to the instructions. They demonstrate the two most common web weaknesses: SQL injection (reading data the application should protect) and reflected cross-site scripting (getting the application to run their script), then submit a capture-the-flag code shown on the XSS result page. No Kali or command line is needed for the primary scored path.

Concepts ​

How untrusted input reaches a SQL query and an HTML response, why input validation and output encoding matter, and the difference between reflected and stored XSS. The guide frames each milestone as a question the student makes the database or page answer.

Topology, roles and machines ​

MachineAddressRoleReached by
dvwa10.0.(50+N).30Target web app and databasePortal proxy only (LXD proxy device on 10.115.77.1:18300+N)
Kali10.0.(50+N).10Optional fallback pathBrowser terminal tab

The DVWA proxy (portal/src/app/lab/dvwa/[[...path]]/route.ts, lib/dvwaProxy.ts) requires a portal session, allows only the SQL-injection, XSS, login, logout, security and asset paths, strips the rest of the DVWA menu, and rewrites HTML, cookies and redirects. Since pull request 256 it also signs the student in: when a page load is bounced to DVWA's login form, the proxy logs in to that student's own DVWA with the stock lab account, pins Security to Low and replays the request, so the lab opens ready to use; DVWA's own login page is the fallback if that fails (lib/dvwaAutoLogin.ts). Since pull requests 225 and 245 it injects a fluid stylesheet (/dvwa-theme/css/embedded.css) so DVWA fits the narrow pane.

The embedded pane (components/scenario/DvwaView.tsx) shows the target IP, a Required: Security Low badge and a strip with only five modules: Home, SQL Injection, XSS (Reflected), DVWA Security and Login. Home, Security and Login load inside the frame. SQL Injection and XSS (Reflected) open in a new top-level tab instead, because the proxy's CSP sandbox isolates them and only a top-level page keeps DVWA's SameSite=Lax session cookie on form submits, which the browser scoring needs. A side cue on Task 1, shown inline under the module strip since pull request 223, warns that DVWA Security must read Low and that the lab sets it.

Tools ​

A web browser is enough. The guide's optional fallback uses curl and sqlmap on Kali; both are preinstalled.

Vulnerabilities ​

  • SQL injection in the DVWA "SQL Injection" module at security Low.
  • Reflected XSS in the DVWA "XSS (Reflected)" module at security Low.

Both exist only in the lab's DVWA container, which is created from the dvwa-base golden image at security level Low and destroyed with the lab.

Milestones, checks and evidence ​

The primary path is browser scoring: as the student's requests and DVWA's responses pass through the portal proxy, detectBrowserMilestone() (portal/src/lib/dvwaScoreSignals.ts) looks for proof in the response and, on a match, calls POST /internal/browser-score with a shared secret. The API records one PASS per milestone (a unique index prevents duplicates).

#MilestonePointsBrowser signal (what proves it)Kali fallback
1Injection Point50An always-true payload returns at least two "First name" rows, or a quote produces a SQL syntax errorA real curl to the SQLi page with an injection payload, or a probe file showing an error or results
2Database Extraction75A UNION SELECT against information_schema/database() whose result shows information_schema or dvwaA users file with user:hash rows
3Admin Hash100A UNION SELECT ... FROM users whose result contains a 32-hex hashA real sqlmap dump command in history plus a 32-hex hash file
4Reflected XSS75A request to the reflected-XSS page with a <script name, reflected as "Hello <script" in the responseA curl of the XSS page in history, or a proof file containing the reflection
5Capture the Flag50Flag-only: the student submits the per-student code (adjective-noun-number, for example brave-otter-7421) that the XSS (Reflected) result page prints under the "Hello" line. Matched case-insensitively.none

Sources: dvwaScoreSignals.ts, pods_router.py (browser_score, _BROWSER_LABELS), check_scenario_6 in scoring_checks.sh, hybrid_scoring.py (PURE_FLAG_MILESTONES), flag_planting.py (generate_capture_flag).

Since pull request 232 the proxy waits up to 5 seconds for the API's answer. If the API rejects the score (for example HTTP 409 because the student's active lab is another scenario or is not active) or does not answer, a banner on the DVWA page says the attack worked but was not scored, instead of failing silently (browserScoreFailureHint() in dvwaScoreSignals.ts).

The browser scorer ignores placeholder values, and the Kali fallback ignores history lines that contain angle-bracket placeholders or echo/printf, so pasting the guide's examples verbatim does not score.

Completion detection ​

A browser PASS short-circuits Manual Check for that milestone (has_browser_pass in scoring.py). Task 5 scores when the code is submitted in the exercise panel. The scenario is complete when all five tasks have a PASS; the score is 350.

Logs and evidence ​

  • milestone_verification rows with detection_data beginning browser: for the browser path.
  • Instructor diagnostics (pull request 267, off unless SCORING_DIAGNOSTICS_SCENARIOS includes 6): when a request is clearly an attempt at one milestone but did not score, the proxy posts only a reason code to POST /internal/browser-diagnostic (same shared secret as browser scoring): SECURITY_NOT_LOW, PAYLOAD_NO_ROWS, QUOTE_NO_ERROR, UNION_NO_METADATA, UNION_NO_HASH or XSS_NOT_REFLECTED (browserNearMiss()). The payload and page are never sent, and a milestone already passed on that lab keeps its PASS. See Lifecycle & Scoring.
  • Per-student flags are planted in the DVWA database and web container as supplementary artifacts for Milestones 1 and 3.
  • The Task 5 code is generated per student with an HMAC of COHORT_FLAG_SECRET (generate_capture_flag()), and provisioning rewrites DVWA's Low-level xss_r/source/low.php so the result page prints it inline. If COHORT_FLAG_SECRET is missing, flag planting fails and Task 5 cannot be completed (D5). No SQL table of flags is seeded any more, so a SQL dump cannot return several candidate flags.

Standards mapping ​

FrameworkMappingNote
MITRE ATT&CK (portal)T1190 Exploit Public-Facing ApplicationApplied to the whole scenario
OWASPNot tagged in codeClosest: A03:2021 Injection (SQL injection and XSS)

Documentation vs implementation ​

D9: there is still no rubric row for scenario 6 milestone 4; rubrics.py now states that M4 "stays browser-scored and needs no rubric". The rubrics endpoint lists M1 to M3 and M5. Browser and history scoring of M4 still work. See Open Questions.

Safety ​

DVWA is never published: it is reachable only through the session-gated portal proxy with a path allowlist. Even a working reflected-XSS payload here cannot read the portal's cookies, because the proxied page has no real origin. The automatic sign-in uses DVWA's stock lab account (already printed in the guide) and only ever reaches the DVWA of the requester's own active lab, found from their session (ownerActivePodId() in the proxy route). The container is unprivileged and destroyed at teardown.

Cyber Range capstone documentation (Capstone 2 · Group 2 · A4102). Documents main at commit 6971373.