Lab Difficulty: Apprentice
Topic: Cross-Site Scripting (Stored)
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.
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>
Vulnerability Assessment
The input lands inside a single-quoted JavaScript string:
tracker.track('INPUT');
Constraints:
Angle Brackets (<>) & Double Quotes ("): HTML-encoded. We cannot break
out of the HTML tag or attribute.
Single Quotes (') & Backslashes (\): Escaped with a backslash.
Input: ' -> Reflected: \'
Input: \ -> Reflected: \\
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 ', the server’s filter
(which looks for literal ') will ignore it. But the browser will decode
' into a literal ' at runtime, allowing us to break out of the
string.
Payload Construction
We crafted a payload that uses HTML entities to smuggle the single quotes past the filter.
Strategy:
Close String: ' (Decodes to ').
Separate: - (Minus operator forces the JS engine to evaluate the expression).
Command: alert(1).
Re-open String: -' (Decodes to -'). This creates a syntactically
valid subtraction operation with the trailing quote from the original code.
Payload:
http:'-alert(1)-'