PortSwigger-Writeups

Lab: Stored XSS into onclick Event with Angle Brackets and Double Quotes HTML-Encoded and Single Quotes and Backslash Escaped

Lab Difficulty: Apprentice

Topic: Cross-Site Scripting (Stored)

1. Objective

The objective of this lab is to perform a Stored Cross-Site Scripting (XSS) attack via a blog comment. The injection point is inside the onclick event handler of a user’s name link. The application employs strict filtering: angle brackets (<>) and double quotes (") are HTML-encoded, while single quotes (') and backslashes (\) are escaped. The goal is to bypass these filters and execute the alert(1) function when the comment author’s name is clicked.

h1

2. Reconnaissance & Analysis

Identification of Injection Point

We began by analysing the comment submission form. We submitted of a comment with the website field set to https://www.example.com. The server reflects the website URL into the onclick attribute of the author’s name link:

<a id="author" href="http://..." onclick="var tracker={track(){}};tracker.track('[https://www.example.com](https://www.example.com)');">hacker</a>

h2

Vulnerability Assessment

The input lands inside a single-quoted JavaScript string:

tracker.track('INPUT');

Constraints:

This escaping mechanism prevents us from closing the JavaScript string using a literal single quote. However, since we are inside an HTML attribute (onclick) the browser performs HTML entity decoding before executing the JavaScript.

Hypothesis: If we inject the HTML entity &apos;, the server’s filter (which looks for literal ') will ignore it. But the browser will decode &apos; into a literal ' at runtime, allowing us to break out of the string.

3. Exploitation

Payload Construction

We crafted a payload that uses HTML entities to smuggle the single quotes past the filter.

Strategy:

  1. Close String: &apos; (Decodes to ').

  2. Separate: - (Minus operator forces the JS engine to evaluate the expression).

  3. Command: alert(1).

  4. Re-open String: -&apos; (Decodes to -'). This creates a syntactically valid subtraction operation with the trailing quote from the original code.

Payload:

http:&apos;-alert(1)-&apos;

h3 h4