Reflected XSS → DVWA Walkthrough: Learn How User Input Can Trigger a Script Execution
2025-11-15 05:56:6 Author: infosecwriteups.com(查看原文) 阅读量:19 收藏

Adwaith S

Press enter or click to view image in full size

🕵Hey! I’m Adwaith, an aspiring offensive security enthusiast, and I’m excited to walk you through the Reflected XSS lab in DVWA, where we’ll see how a simple input field can lead to script execution.

Click the link below, deploy DVWA, and join me on this walkthrough journey.

https://hub.docker.com/r/vulnerables/web-dvwa

Before we jump into Reflected XSS, if you’re new to this, you should know a few basic web concepts. Don’t worry, it’s easy! Just look at the section below and you’ll get it instantly.

Press enter or click to view image in full size

A website is built from three layers, and we interact with all of them.

HTML (the page structure - headings, paragraphs, inputs)
CSS (visual style - colors, fonts, layout)
JavaScript (behavior — what runs after the page loads)

Only three layers? You might be wondering what nonsense I’m talking about. I was talking about the front end, but do we also need to discuss the backend?
Relax I’m not here to teach full-stack web development. This is just for basic understanding. If you’re already a web developer, you can skip this part. It’s meant for beginners.

Press enter or click to view image in full size

[ GIF sourced from gifs9z. Rights belong to the creator. ]

Now listen! JavaScript can change a webpage by reading and updating its elements. When a site takes user-provided text (like a name, a search query, or a URL parameter) and inserts it directly into the HTML without cleaning or validating it, the browser will treat that text as code and execute it.
That’s the root of XSS.

 bad input + trusted browser = attacker-script execution.

Don’t worry DVWA is local and safe while you try this. So let’s understand the basics. Look at the HTML code below:

<!DOCTYPE html>
<html>
<body>

<h2>My First JavaScript</h2>

<button type="button"
onclick="document.getElementById('demo').innerHTML = Date()">

Click me to display Date and Time.</button>

<p id="demo"></p>

</body>
</html>

What do you think these are?
Okay, first of all, if you come from a computer science background, you’ve definitely learned about HTML, CSS, and JavaScript even if you’ve forgotten them. And if you’re from another field, don’t worry. I’ve got you covered!

HTML, CSS, JAVASCRIPT

Why am I giving this link? Because if I start explaining HTML, tags, and everything here, the write-up will become too long. W3Schools is a beginner-friendly platform where you can learn HTML easily and not just HTML, it also has many other beginner-friendly coding tutorials.
And listen, you don’t need to understand everything. Just learn some basic HTML tags and the page structure (like the <body> ). That’s it. It won’t take much time!

Line-by-line explanation:

Html

<!DOCTYPE html>               -> Tells the browser this is an HTML5 page.
<html> -> Root element of the webpage. Everything visible goes inside this.
<body> -> The part of the page that the user sees (content, buttons, text).
<h2>My First JavaScript</h2> -> A level-2 heading (big, bold title). This just shows the page title "My First JavaScript".

</body> -> Closing tags for the body and html
</html>

JavaScript

<button type="button" onclick="document.getElementById('demo').innerHTML = Date()">
Click me to display Date and Time.</button>

Line-by-line explanation:

<button type="button">...</button>   -> A clickable button on the page.

onclick="..." -> This is an inline event handler: when the button is clicked, the code inside the quotes runs.

document.getElementById('demo') -> JavaScript asks the page for the element with the id demo (below).

.innerHTML = Date() -> This sets that element's HTML content to the value returned by Date() (the current date/time).

<p id="demo"></p> -> <p> A paragraph element, id="demo" Gives this paragraph a name so JavaScript can find it (getElementById('demo')). It starts empty; clicking the button fills it with the current date/time.

This page shows how HTML and JavaScript work together, HTML defines the structure (heading, button, paragraph) and JavaScript runs when you click the button to change the page.

Date() returns the current date and time. innerHTML writes that value into the paragraph with id = “demo” so the user sees it.

Press enter or click to view image in full size

[ output ]

We talked about HTML and JavaScript, and I hope you understood the basics. That’s enough for now well, technically it’s not enough, but don’t worry. I was mainly referring to JavaScript. There are many different concepts in JavaScript, and you’ll learn them later, so I’m not going to make things messy here. Alright, let’s get back to XSS.

Press enter or click to view image in full size

[ Cross-Site Scripting - XSS ]

If you’ve never heard of XSS before, no worries. Cross-Site Scripting (XSS) it’s a client‑side attack where an attacker tricks a website into running their JavaScript inside someone else’s browser. That injected code can show fake interfaces, steal cookies, or change page content, basically anything the browser can do on that site.

Why does XSS work?

Browsers trust the HTML and JavaScript a site gives them. If the site accidentally includes text from a user (like a name or a URL parameter) directly into the page without escaping or sanitizing it, the browser will treat that text as code.

Types of XSS:

Reflected XSS  (non‑persistent)
Stored XSS (persistent)
DOM‑based XSS (client‑side)
Self XSS (social‑engineering)

What is Reflected XSS?
Reflected XSS happens when user input (from a URL or form) is immediately included in a page response without sanitizing it, causing browser-side script execution, Here is an real scenario.

Press enter or click to view image in full size

[ Reflected XSS ]

How Reflected XSS actually happens (step-by-step)

1 - User input point: The site has a form, search box, or URL parameter that is echoed back on the page (e.g., “Hello, {name}”).

2 - Attacker crafts a URL containing malicious JavaScript in that input (for example, in the ?name= parameter).

3 - Victim clicks the URL (phishing, forum link, etc.).

4 - Server reflects the input into the HTML response immediately (no save to DB).

5 - Browser parses the response and executes the injected script. Boom attacker script runs in the victim’s session/context.

You might be thinking about parameters, sessions, cookies, tokens… and a lot more. What are those, and why do attackers steal them? Don’t worry, I’ll explain all of that later. For now, let’s start our first attack on DVWA.
But before we jump into DVWA, you need to know this payload.

Payload:

<script>alert('xss')</script>

Don’t forget this. It’s just a simple payload actually, it’s just JavaScript. We use this payload to check whether a website is vulnerable to XSS. And remember, this isn’t the only one; there are many different payloads for different situations. I’m not going to complicate things now we’ll explore more payloads later. You can even run this directly in your browser. Just press F12 to open Developer Tools.

Press enter or click to view image in full size

[ Console ]

Here, choose the Console tab. It will appear like a command prompt. Now just run the payload without the <script> tag.

alert('xss')

Now just run the payload:

Press enter or click to view image in full size

[ Console ]

You will see a pop-up appear in your browser.

Press enter or click to view image in full size

[ popup ]

So this is a sign of an XSS attack! You might be thinking, ‘Is this happening in our browser?’ Absolutely but did we trigger it from a website? No.
Remember, I told you to remove the <script> tag before running the payload in the Console. That’s because we’re running it directly in the JavaScript console, and the console accepts any JavaScript code we give it.

note:

when we are testing on website we will look for (search box) or an input field to test xss but that time we will include <script> tag. because if the site echoes it back without escaping, the browser will run it

[ GIF sourced from icegif. Rights belong to the creator. ]

You know something? There’s an attack called Self-XSS. It’s basically the same thing we just did. An attacker tricks a user through social engineering, and the user ends up copy-pasting a malicious script into their browser console. That script can steal credentials like cookies, sessions, or tokens. But remember this kind of attack never jumps from your browser to your computer. It stays inside the browser because these are browser-based attacks.
Before we move on, look below and understand what cookies and sessions are. These are important basics you need to know when working with the web.

What are Cookies?

Cookies are small pieces of data that a website saves in your browser. They help the site “remember” things like your login, theme, or what’s in your cart even after you leave or refresh the page.

Example: When you log in to a site and come back later without logging in again that’s because of cookies.

What are Sessions?

Sessions are like temporary memory on the server. When you log in, the website creates a session with your info (like your username or ID) and gives your browser a small cookie (called a session ID) to link you to that data.

Example: When you move between pages after logging in, the site knows it’s still you because your session is active.

If we are talking in simple way:

Cookies = stored in your browser (client-side)

Sessions = stored on the website’s (server-side)

They work together to keep you logged in or track your activity safely.

I hope you understood how cookies and sessions work. You might wonder why I didn’t mention tokens because this write-up would become too long, and there’s a lot more to explain about tokens. We’ll learn about them later.
For now, just keep in mind how cookies and sessions work. If you’re eager to learn about tokens, feel free to research them on your own. Alright, let’s get into the DVWA lab.

Vulnerability: Reflected Cross Site Scripting (XSS)

[ Security-Level : LOW ]

Press enter or click to view image in full size

[ Input field ]

What we see here is an input field with a submit button. It asks, ‘What is your name?’ Let’s find out what’s happening behind the scenes.

Press enter or click to view image in full size

[ Input field ]

Here you can see that whatever we type is echoed back on the page. Also, there’s something important you should notice the URL bar.

Press enter or click to view image in full size

[ URL bar ]

Whatever you type in the input field is also being passed in the URL.

name={name}#

this thing (name = ) we called as parameter, keep in your mind.

[ Testing XSS Payload ]

Press enter or click to view image in full size

[ Input field ]

So now we’re going to test our XSS payload here.

<script>alert('xss')</script>

Place this script in the input box and then click Submit.

Press enter or click to view image in full size

[ Input field]

Here is the result:

Press enter or click to view image in full size

[ URL bar ]

Boom! We’ve triggered the XSS!

Here is the source code. Let’s see what’s happening behind the scenes:

<?php

header ("X-XSS-Protection: 0");

// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Feedback for end user
echo '<pre>Hello ' . $_GET[ 'name' ] . '</pre>';
}

?>

In this code, the user’s input from the URL $_GET[‘name’] is printed directly onto the page using echo, without any escaping or filtering.

That means if someone types something normal like:

?name=Adwaith

the page shows

Hello Adwaith

But if someone enters a script instead, like:

?name=<script>alert('XSS')</script>

the browser doesn’t see it as plain text it sees a real <script> tag and runs the JavaScript.

This happens because the server just echoes whatever the user gives it, and the browser trusts the HTML it receives. That’s the core of Reflected XSS, user input reflected in the response without escaping or validation.

When we look at the URL, it might look a bit messy.

name=%3Cscript%3Ealert%28%27xss%27%29%3C%2Fscript%3E#

It’s called URL encoding. Jut know that When we send something through a website’s input form, special characters like( ?, &, =, <, >, ) and even spaces are encoded so they can be properly understood by the web server.

If you want to see the original value, just paste it into CyberChef.

When you decode it, it looks like this.

name=<script>alert('xss')</script>#

We can now see the actual payload. In BurpSuite, we can easily decode it without using any external website just select the URL-encoded string, and Burp will show you the original form right there.

So how do hackers use this XSS attack against a victim? Here’s a demo:

What did you understand from this video? Just think for a moment. If you didn’t get it, I’ll explain it. I copied the entire URL and pasted it into a new tab, and it still triggered the XSS.
Why did it work in a new tab? And why did it work without pasting the XSS payload into the input field? How was it triggered without using the input box? Look here:

Press enter or click to view image in full size

[ Input field ]

We enter the name in the input field and then click Submit.

Press enter or click to view image in full size

[ URL bar ]

What do you see here? A parameter carrying the name we typed in the input field. So think of the input field as just a medium or channel. It takes our input, sends it into the parameter, and then that gets sent to the web server.

http://172.17.0.1/vulnerabilities/xss_r/?name=adwaith#

If you copy and paste it into the URL, it also works it prints or echoes the name. The same thing happens when you copy-paste the XSS payload.

http://172.17.0.1/vulnerabilities/xss_r/?name=%3Cscript%3Ealert%28%27xss%27%29%3C%2Fscript%3E#

Result:

Press enter or click to view image in full size

[ xss ]

If a hacker tests a field and finds that it’s vulnerable to XSS, then the attacker can craft a malicious payload.

name=<script>malicious_payload</script>#

The attacker will replace the normal payload, like alert(‘xss’), with a malicious payload that can steal the victim’s cookies.

http://172.17.0.1/vulnerabilities/xss_r/?name=<script>malicious_payload</script>#

Then the attacker sends that crafted URL to the victim. If the victim clicks the URL, the malicious XSS payload will execute, grab the victim’s cookies from their browser, and send them to the attacker’s server.
Finally, the attacker can gain access to the victim’s account without needing the password.

Press enter or click to view image in full size

[ xss ]

See how impactful an XSS attack can be.

[ GIF sourced from tenor. Rights belong to the creator. ]

It’s just a pop-up here, but when used the right way, XSS can cause major impact. It’s not only about account takeover sometimes it can expose sensitive data like PII, payment details, secrets, private messages, or tokens.

We discussed this attack in the context of a targeted user through Reflected XSS. But what if I told you it can affect many users over time? That’s called a Stored (Persistent) XSS attack.

In a stored XSS scenario, the attacker only needs to craft the payload once and inject it into a vulnerable page. From that moment, every user who visits that page will trigger the XSS no need to send URLs or parameters manually. And imagine if one of those users is an admin… the attacker can compromise the admin account too. We’ll discuss this attack in detail in a future section.

[ Security-Level : MEDIUM ]

Let’s put the payload again:

Press enter or click to view image in full size

[ Input field ]

Now you can see that our payload isn’t working here. When you look at the response, it’s being treated as plain text. But why isn’t the <script> tag printed? We can assume it’s being ignored or filtered. We actually increased the security level a bit. So does this mean XSS doesn’t work here? Nope. What would you do in this situation?

There are different ways to bypass filters, so listen carefully, if our payload doesn’t work, they might be filtering it. We need to craft suitable payloads and keep testing different variants until one succeeds. So how do we craft the payload?

First, I’ll show you how it’s done:

Press enter or click to view image in full size

[ Input field ]

Just submit this payload!

Press enter or click to view image in full size

[ xss ]

Boom! We triggered the XSS again…

Why did it work? Just observe the payload:

First Payload:

<script>alert('xss')</script>

Second Payload:

<Script>alert('xss')</Script>

Take a look at both payloads and see the difference. Notice the tag we used I changed <script> to <script>. The filter was misconfigured, so it only blocked lowercase <script> and didn’t block <script>. If you didn’t understand that, don’t worry. Just look here—let’s see what’s happening behind the scenes.

<?php

header ("X-XSS-Protection: 0");

// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Get input
$name = str_replace( '<script>', '', $_GET[ 'name' ] );

// Feedback for end user
echo "<pre>Hello ${name}</pre>";
}

?>

Look here at this specific area:

$name = str_replace('<script>', '', $_GET['name']);
echo "<pre>Hello ${name}</pre>";

look the conditon in here it only removes the exact string “<script>”(lowercase, no spaces, no attributes), so that means what ever we input the payload expect <script> , so what will happen next?

the PHP’s str_replace is case‑sensitive, so it will not remove:

<Script>
<SCRIPT>
<script >

So we can craft payloads using different tag variations and still trigger XSS. Pretty cool, right? But how do we find the right payload? In real scenarios, you don’t have access to the source code to see the misconfiguration. So how do you figure it out? It’s up to you by understanding how the input field works and how the response is reflected back. Like I said earlier, just start by putting the normal payload:

<script>alert('xss')</script>

You’ve understood how the response looks, but you can also inspect the source of webpages by pressing F12 or opening the Developer Tools. This way, you can understand how it works too.”

Press enter or click to view image in full size

[ Dev tools ]

You’ve learned two things: you can understand how the application behaves by looking at the echoed response or inspecting the page with Developer Tools, and you can craft different payloads depending on the situation.

here is the useful resource, save it somewhere it may very helpful:

You can easily craft different types of XSS payloads from here.

[ Security-Level : HIGH ]

Let’s test some payloads:

Press enter or click to view image in full size

[ Input field ]

Not working. Okay, let’s try the next payload.

Press enter or click to view image in full size

[ Input field ]

It’s not working! But what’s happening here? The security has been increased, and earlier the filtering was misconfigured but now they’ve fixed that too. First, look at the response: it echoes as ‘Hello >’ and doesn’t show the full payload. This means we can understand that the input is being filtered.

<script>
<Script>

But the > character was still echoed, so we can assume that the <script> tag is being filtered. I tried different variations of the <script> tag, but none of them worked. But as I said earlier, whenever we see an input field, we should always test this payload.

<script>alert('xss')</script>

But in your mind, you might think about changing <script> to <Script> or SCRIPT, but it’s not working here. So the question is: can we trigger XSS without using the <script> tag? Is it possible to use a different tag?

Yes, absolutely. I already told you before that we can craft XSS payloads in different ways based on different situations. So I hope you checked the XSS cheat sheet I shared earlier in the Medium level.

When you look at the cheat sheet, you’ll notice I crafted a suitable payload that can trigger XSS and it doesn’t even use the <script> tag.

Press enter or click to view image in full size

[ Cheat sheet ]

Let’s test it:

Press enter or click to view image in full size

[ Input field ]

Just submit the payload:

Press enter or click to view image in full size

[ xss ]

Boom! We triggered the XSS again…

Let’s examine our payload:

<img src/onerror=alert('xss')>

This creates an image element. The browser tries to load the image from src and when it fails, the onerror event runs and that event can contain JavaScript. So the alert(‘xss’) runs when the image load fails. A more common, clearer form is:

<img src=x onerror=alert('xss')>

Here src = ‘x’ is an invalid image URL so the image fails to load and onerror fires.

If you don’t know how the <img> tag works or how to use it, here’s a reference:

Here is the demo:

What is onerror?

onerror is an HTML event attribute. It tells the browser what to do when something goes wrong, like when an image or script fails to load.

<img src=x onerror=alert('xss')>

If the browser can’t find ‘x’ it triggers the onerror event and runs the JavaScript there we palced the alert function alert(‘xss’) .

Let’s look at what’s happening behind the scenes:

<?php

header ("X-XSS-Protection: 0");

// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Get input
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] );

// Feedback for end user
echo "<pre>Hello ${name}</pre>";
}

?>

The app only looks for the word script and removes that.The attacker used img + onerror, which is a different way to run JavaScript.Result: the filter misses it, the browser executes the onerror code, and XSS happens.

[ Security-Level : IMPOSSIBLE ]

Press enter or click to view image in full size

[ xss ]

They’ve added more security to prevent XSS attacks:

<?php

// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

// Get input
$name = htmlspecialchars( $_GET[ 'name' ] );

// Feedback for end user
echo "<pre>Hello ${name}</pre>";
}

// Generate Anti-CSRF token
generateSessionToken();

?>

It’s impossible to perform XSS here, they’ve effectively prevented reflected XSS.

What this code does:

1, It checks if the page received a name value in the URL (like ?name=adw..)

2, It calls checkToken(…) to validate a CSRF token (that’s for preventing cross-site request forgery a different security problem).

A CSRF token is like a secret handshake between your browser and the website only real forms from the site know it, so attackers can’t fake your actions.

3, It runs the input through htmlspecialchars() this turns < into &lt; and > into &gt; , so any <script> a user sends becomes plain text instead of code.

4, Then it prints Hello {user} inside the page. Because the input was escaped, the browser shows the raw characters and won’t run any JavaScript, so this prevents reflected XSS in this place.

[ GIF sourced from tenor. Rights belong to the creator. ]

If you suspect an XSS‑vulnerable field, try every possible payload. Check the response, inspect the page, craft payloads from cheat sheets, and keep testing even if it fails, try again and again until it succeeds. You can discover different tags, events, and bypass tricks for different situations. In real‑world applications, you’ll face WAFs (Web Application Firewalls), rate‑limiting, and many stronger protections than these basic filters. That’s why you must research, explore bypass techniques, and stay updated.

Here are some useful references on filter‑bypass methods hope they help:

Thanks for coming! Stay curious, stay ethical!

Follow me for more about cybersecurity: Medium, Github, LinkedIN


文章来源: https://infosecwriteups.com/reflected-xss-dvwa-walkthrough-learn-how-user-input-can-trigger-a-script-execution-3c9f9f26962b?source=rss----7b722bfd1b8d---4
如有侵权请联系:admin#unsafe.sh