Again another article about XSS.
This time we are going to see DOM XSS on DVWA, and the practical exploitation of the vulnerability.
As you may have already guessed I particularly push for hands-on learning, in this case, there is not so much different from what we have seen previously, except for some details.
I also wanted to address this specific walkthrough just because in the real world, often the difference between a working exploit and a not working one is only a single little detail.
Obviously, throughout the following write-up, I will take for granted all the knowledge already covered in the previous articles.
In case there are any gaps, I recommend you to read the following tutorials before proceeding:
- The terrifying world of Cross-Site Scripting (XSS) (Part 1)
- The terrifying world of Cross-Site Scripting (XSS) (Part 2)
- XSS in practice: how to exploit XSS in web applications
- Reflected XSS DVWA – An Exploit With Real World Consequences
- How to exploit a stored XSS vulnerability on DVWA
- How to exploit DOM XSS on DVWA
When you are ready, you can prepare your DVWA machine (I’m using the one on TryHackMe), if you don’t know how to do it, I explained it in a nutshell in this article: How To Hack With SQL Injection Attacks! DVWA low security.
After this quick introduction, I am sure you will be ready to get your hands dirty and make all the concepts covered your own for real.
Step #1. DOM XSS on DVWA with low security
The first step after the initial setup is to log into the machine with the default credentials:
- Username: admin
- Password: password
After that, go into the settings on the left side menu and set the security as low (remember that the default security is “impossible”).
We have to repeat this action every time we need to change the security level.
Finally, the initial preparation is over and we can begin with the actual exploit!
By now we should know that the first level is just a kind of warm-up, as usual in DVWA, so let’s try the basic exploit and see the result!
To do that we need to identify the vulnerable input.
By selecting the language (English for example) and clicking on the “Select” button, the URL changes in this way (the IP address depends on the DVWA instance):http://10.10.37.210/vulnerabilities/xss_d/?default=English
So the value is passed as a GET value into the query string, and that will be our target.
Try for example to replace that value with something random, like this:
http://10.10.37.210/vulnerabilities/xss_d/?default=StackZero
We can see that the parameter is reflected in the default item of the dropdown menu:
Just in case, let’s try to inspect the code of the dropdown menu (Right click + Inspect(Q) in Firefox):
<select name="default">
<script>
if (document.location.href.indexOf("default=") >= 0) {
var lang = document.location.href.substring(document.location.href.indexOf("default=") + 8);
document.write(" < option value = '" + lang + "' > " + decodeURI(lang) + " < /option>");
document.write(" < option value = ''
disabled = 'disabled' > -- -- < /option>");
}
document.write(" < option value = 'English' > English < /option>");
document.write(" < option value = 'French' > French < /option>");
document.write(" < option value = 'Spanish' > Spanish < /option>");
document.write(" < option value = 'German' > German < /option>");
</script>
<option value="StackZero">StackZero</option>
<option value="" disabled="disabled">----</option>
<option value="English">English</option>
<option value="French">French</option>
<option value="Spanish">Spanish</option>
<option value="German">German</option>
</select>
By looking at the script, it’s clear that the default value is taken from the URL using the function: document.location.href.substring(document.location.href.indexOf("default=") + 8);
The index of “default=” + 8 indicates the position after 7 chars of the word “default” plus one char of the equals (remember that the index counter starts from zero).
We have already seen this kind of client-side elaboration in this article.
So we could try to set the default value with a string representing our basic exploit by typing this URL in our browser:http://10.10.37.210/vulnerabilities/xss_d/?default=<script>alert('You have been hacked!');</script>
And exploit worked, so we can move on to the next level!
Step #2. DOM XSS on DVWA with medium security
We are at the medium level, and the first thing we can do is try the exploit of the previous level, but obviously, it doesn’t work.
Due to that, we can infer that there is some kind of server-side filtering which blocks the <script>
tag.
In the article Reflected XSS on DVWA, we tried to bypass the filter by typing the tag with some uppercase characters, but in this case, it will be ineffective, we should come up with more.
By inspecting the dropdown menu, we are dealing with select
and option
tags, so we couldn’t think to put an image and take advantage of the onerror event as we did in past (or maybe something similar).
Apart from the deletion of the script tag, it seems to don’t have other string processing routines, so closing the select tag and inserting our exploit would seem to be a very good idea.
In HTML the embed tag is a container for an external resource, so we will use that to pass this level and we will set our default variable with this value:
</select> <embed src="javascript:alert('You have been hacked')">
Such that the crafted URL will appear like this:
http://10.10.37.210/vulnerabilities/xss_d/?default=</select> <embed src="javascript:alert('You have been hacked')">
And the level is passed again!
If you want to explore more exploits and maybe test them here, you might take a look at this cheatsheet.
Now it’s time to carry on, so set the security level to “high” and jump to the next level!
Step #3. DOM XSS on DVWA with high security
Finally, we are at the final level, you can try by yourself all the previous techniques, but unfortunately, this time they don’t seem to be working.
There is a filter harder to bypass, in order to have an idea, this time we can cheat a bit and look at the “View Source” so that we can see the PHP of the server.
This is the filter we are going to bypass:
<?php
// Is there any input?
if (array_key_exists("default", $_GET) && !is_null($_GET["default"])) {
# White list the allowable languages
switch ($_GET["default"]) {
case "French":
case "English":
case "German":
case "Spanish":
# ok
break;
default:
header("location: ?default=English");
exit();
}
} ?>
It will just accept one of the predefined voices, and even if it doesn’t seem to have a solution, we can still do something.
Before proceeding there is something we need to know about how a browser interprets a URI:
The query component is indicated by the first question mark (“?”) character and terminated by a number sign (“#”) character or by the end of the URI
RFC 3986 Section 3.4
If you want to know more, this is the link.
So the browser sends to the server as a query string what is between “?” and “#” but it processes the substring from the index of “default=” + 8 with its javascript (as we have seen in the first step with low-security level).
We want to send the right query string to the server, terminate that by typing “#” and then insert our exploit.
Let’s see how to do that and then discuss a little bit after, this is our exploit:
#<script>alert("You have been hacked");</script>
And here is the complete malicious URL.
http://10.10.173.217/vulnerabilities/xss_d/?default=English#<script>alert("You have been hacked );</script>
But what happens with this crafted URL?
The server receives this URL:
http://10.10.173.217/vulnerabilities/xss_d/?default=English
So it doesn’t trigger the filter because is correct and the server is happy!
Meanwhile, the browser will copy this string in its lang variable and then reflect in its page:
English#<script>alert("You have been hacked );</script>
So if we inspect the element this should be the result (I just reported the part of interest):
<option value="English#%3Cscript%3Ealert(%22You%20have%20been%20hacked%22);%3C/script%3E">English# <script>
alert("You have been hacked");
</script>
</option>
<option value="" disabled="disabled">----</option>
<option value="English">English</option>
<option value="French">French</option>
<option value="Spanish">Spanish</option>
<option value="German">German</option>
Let’s connect to the URL and see the result!
It works again, so we are done and even this section is complete! We can be proud of ourselves!
Conclusion
This kind of XSS is not as common as the other types, but knowing that can lead you either to avoid many errors as a programmer or to get some bounty as a white hat hacker.
I recommend that you practice as much as possible to master the concepts and make them natural.
There are a lot of challenges on the web and you are prepared to face them!
In future posts we will see how dangerous can be such a vulnerability with some examples, so stay tuned!
I hope the explanation was exhaustive, I enjoyed a lot writing this post!
If you like this kind of article, please keep following my blog and social.
Thank You!