Welcome to the CSE1CPR Web Security Training Environment. This self-contained simulator lets you practice real web attack techniques without needing a network connection or external accounts.
You will work through 10 progressive challenges, each teaching a different vulnerability category. Read each level carefully, use the tools provided (View Source, Dev Tools), and find the password or flag to advance.
L1 — Reading HTML source code
L2 — Logic flaws (empty password)
L3 — Directory traversal / hidden files
L4 — DOM manipulation via browser dev tools
L5 — Cookie / session tampering
L6 — Chosen-plaintext cryptanalysis
L7 — OS command injection
L8 — Cross-Site Scripting (XSS)
L9 — JWT token forgery
L10 — SQL Injection
Each challenge is worth 100 points. Record your answers and methods in your lab report as you go.
01
Reading HTML Source
HTML / Reconnaissance
Background: Web pages are plain text delivered by the server. Developers sometimes leave sensitive information — including passwords — inside comments or hidden form fields. Every browser lets you read the full source with Ctrl+U or right-click → View Page Source.
Your task: find the password hidden in the page source and submit it below.
🔍 Hint
Click "View Page Source" below. Look for HTML comments (<!-- … -->) and hidden input fields.
http://websec-lab.internal/basic/1/
Sam's Super Secure Login
Enter the password to continue.
<!DOCTYPE html><html><head><title>Sam's Login</title></head><body><h2>Sam's Super Secure Login</h2><formaction="login.php"method="POST"><!-- TODO: Remove before deployment! Password is: s3cr3t_p4ss --><inputtype="password"name="pw"><buttontype="submit">Submit</button></form></body></html>
🏆
Level 1 Complete! +100 ptsThe password was in an HTML comment — invisible to users but visible to anyone who views source. Classic developer mistake.
02
Logic Flaws — Empty Password
Application Logic
Background: Sam forgot to set a password. The server checks if the submitted password matches the stored one — but if nothing is stored, an empty string matches an empty string. Try submitting with the password field completely blank.
http://websec-lab.internal/basic/2/
Challenge 2 — Admin Portal
Sam hasn't set a password yet. The system is "secure for now."
/* server-side PHP pseudocode */$stored_password = ""; // Sam hasn't set one yet!if ($_POST['password'] == $stored_password) {
echo"Welcome, admin!"; // BUG: "" == "" is TRUE
} else {
echo"Wrong password.";
}
🏆
Level 2 Complete! +100 ptsAn empty password matches an empty stored password. Always validate a password has been set before comparing.
03
Hidden Files in the Web Root
Information Disclosure
Background: The page source references an external file in the same directory. Web servers often expose files that developers assumed were private. If you can guess or discover the filename, you can navigate directly to it.
Look at the page source to find the filename, then navigate to it to retrieve the password.
🔍 Hint
The source has a hidden input with a value attribute containing the config filename. Navigate to that filename — it lives in the same directory.
http://websec-lab.internal/basic/3/
Challenge 3 — Password Lookup
The password is loaded from an external file. Enter the filename in the navigator below.
Level 3 Complete! +100 ptsFiles referenced in HTML source can be fetched directly. Never store sensitive data in the web root.
04
DOM Manipulation via Dev Tools
Client-Side Bypass
Background: The email below is hard-coded into a hidden input field. When you click "Send Password", it emails that address. Because DOM fields are client-side, you can modify them in Dev Tools to redirect the email to yourself.
Use the Dev Tools panel below to change the email value, then click "Send Password."
🔍 Hint
Open the Dev Tools panel → click the yellow editable field → type any email address that is NOT sam's → then click the button.
http://websec-lab.internal/basic/4/
Challenge 4 — Password Reset
Click the button to send the password to the email address stored in the hidden field.
Hidden field value: sam@websec-lab.internal
<formaction="send_password.php"method="POST"><input type="hidden" name="email" value="sam@websec-lab.internal"><button>Send Password to Email</button></form><!-- Server emails whatever address is in the hidden field -->
💡 Click the yellow value field and change the email address. Then click "Send Password."
🏆
Level 4 Complete! +100 ptsHidden fields are not hidden from attackers. Never trust client-supplied values — validate server-side.
05
Cookie & Session Tampering
Client-Side Trust
Background: This site stores your access level in a cookie: role=guest. The server reads this cookie and grants or denies access. Cookies are stored client-side and can be freely modified by an attacker.
Steps: (1) Open the Dev Tools panel below. (2) Click the yellow guest value and change it to admin. (3) Click "Access Admin Dashboard."
🔍 Hint
In a real browser: F12 → Application/Storage tab → Cookies → double-click the role value. Here, use the Dev Tools panel below. Make sure you type admin exactly (lowercase, no spaces).
http://websec-lab.internal/basic/5/
Challenge 5 — Access Control
Current session cookie: role=guest
Admin dashboard requires role=admin.
▶ Storage ▼ Cookies — http://websec-lab.internal
Name
Value
Path
session_id
a3f92bc1deaf4501
/
role
/
theme
dark
/
💡 Click the yellow guest value in the table → clear it → type admin → then click "Access Admin Dashboard."
🏆
Level 5 Complete! +100 ptsCookies are fully user-controlled. Never store authorization decisions in cookies without cryptographic signing (signed JWTs or server-side sessions).
06
Chosen-Plaintext Cryptanalysis
Cryptography
Background: The site uses a simple substitution cipher (each letter maps to a fixed different letter). You can encrypt any string — a chosen-plaintext attack.
By encrypting the full alphabet, you can build a complete plaintext→ciphertext mapping, then reverse it to decrypt the stored password:
🔍 Hint
Encrypt abcdefghijklmnopqrstuvwxyz all at once. The mapping table will fill automatically. Then look up each letter of the encrypted password in the "Cipher → Plain" column.
http://websec-lab.internal/basic/6/
Challenge 6 — Encryption Oracle
Encrypted target:
Encrypt strings to reverse-engineer the cipher, then submit the decrypted password.
Mapping table (encrypt alphabet to fill):
Plain → Cipher
Plain
Cipher
Cipher → Plain (use this to decrypt!)
Cipher
Plain
🏆
Level 6 Complete! +100 ptsSimple substitution ciphers are trivially broken with chosen-plaintext attacks. Always use modern authenticated encryption (AES-GCM, ChaCha20-Poly1305).
07
OS Command Injection
Injection / RCE
Background: This page passes user input directly into a Unix shell command without sanitisation: shell_exec("cal $month $year")
In Unix shells, a semicolon ( ; ) separates commands. Injecting ; ls lists the directory; ; cat password.txt reads the file. Both outputs are returned.
🔍 Hints
Step 1: In the Month field type 5 ; ls and click Show Calendar — you'll see the directory listing.
Step 2: Find the password file name, then type 5 ; cat password.txt to read it.
Step 3: Enter just the flag value (after "FLAG: ") in the submission box.
Level 7 Complete! +100 ptsCommand injection is critical (OWASP Top 10 #3). Never pass user input to shell functions — use parameterised APIs instead.
08
Cross-Site Scripting (XSS)
Injection / XSS
Background: Cross-Site Scripting (XSS) occurs when a web application includes user-supplied data in its output without proper encoding. An attacker can inject JavaScript that runs in other users' browsers — stealing cookies, redirecting to phishing pages, or performing actions on behalf of the victim.
This comment box reflects input directly back to the page. Inject a script tag to trigger an alert — proving code execution.
🔍 Hint
Try posting a comment containing: <script>alert('XSS')</script>
Or an image tag: <img src=x onerror="alert('XSS')">
Once your XSS fires, the flag will be revealed below.
http://websec-lab.internal/basic/8/
Challenge 8 — User Comments
Leave a comment below. All comments are shown to every visitor.
Level 8 Complete! +100 ptsXSS allows attackers to execute arbitrary JavaScript in victims' browsers. Always HTML-encode user output with htmlspecialchars() or your framework's equivalent.
09
JWT Token Forgery
Authentication Bypass
Background: JSON Web Tokens (JWTs) are used for authentication. A JWT has three parts: header.payload.signature, all Base64url-encoded. Some servers have a critical bug: they accept the algorithm "alg":"none", meaning no signature is required.
Your current token has "role":"user". Forge a new token with "role":"admin" and "alg":"none" (empty signature) to gain admin access.
🔍 Hint
Use the decoder below to inspect your token. Then craft a forged token:
Header: {"alg":"none","typ":"JWT"} → Base64url encode it
Payload: {"user":"sam","role":"admin"} → Base64url encode it
Signature: leave empty
Final token: encodedHeader.encodedPayload. (trailing dot, no signature)
Background: SQL Injection occurs when user input is embedded directly into a SQL query without sanitisation. An attacker can manipulate the query logic to bypass authentication, extract data, or destroy databases.
The login query is: SELECT * FROM users WHERE username='INPUT' AND password='INPUT'
By injecting ' OR '1'='1, you can make the WHERE clause always true.
🔍 Hints
Classic bypass: username = ' OR '1'='1' -- (the -- comments out the rest of the query)
Or: username = admin'-- to log in as admin without knowing the password.
Leave the password field blank or with anything.
http://websec-lab.internal/basic/10/
Challenge 10 — Database Login
Login to the admin panel. Credentials are stored in the database.
/* Vulnerable PHP — string concatenation */$user = $_POST['username'];
$pass = $_POST['password'];
$sql = "SELECT * FROM users
WHERE username='$user'
AND password='$pass'"; // VULNERABLE!$result = $db->query($sql);
if ($result->num_rows > 0) {
echo"Welcome, Admin!";
}
// Fix: use prepared statements with bound parameters
// $stmt = $db->prepare("SELECT * FROM users WHERE username=? AND password=?");
// $stmt->bind_param("ss", $user, $pass);
🏆
Level 10 Complete! +100 ptsSQL injection is one of the oldest and most dangerous vulnerabilities. Always use parameterised queries / prepared statements. Never concatenate user input into SQL.
🎖️
ALL LEVELS COMPLETE
Final Score: / 1000
Vulnerabilities Practised
Record your findings and exploitation methods in your lab report.