DVWA Stored XSS Exploit
In my previous article on DVWA, I have demonstrated how to exploit reflected XSS vulnerability at low, medium, and high security in the DVWA web app and we have also reviewed the PHP code which was running on the server. In this article, I will show you how to exploit Stored XSS vulnerability in the same web application at low, medium and high security simultaneously by reviewing their source code. This article is written from a very beginner’s point of view, keeping in mind you don’t know anything about XSS.
If you have directly reached to this article then I will suggest you to read my previous post on DVWA reflected XSS where I have introduced about XSS vulnerability, why it arises, and the types of XSS vulnerability. Before we begin to exploit this vulnerability in the DVWA web application, let us know about Stored XSS vulnerability
in detail.
What is Stored XSS vulnerability?
Unlike Reflected XSS
, Stored XSS is the most dangerous cross-site scripting vulnerability. This type of vulnerability arises whenever a web application stores user-supplied data for later use in the backend without performing any filter or input sanitization. Since the web application does not apply any filter therefore an attacker can inject some malicious code into this input field. This malicious code can also be a valid XSS payload. So whenever any person visits the vulnerable page where malicious code is injected he will get a popup on his browser window. This will prove that the given webpage is vulnerable to Stored XSS vulnerability.
Let us understand it with an example. Suppose you are reading an article at a website https://xyz.com/article.php and there is a comment section at the bottom of the post to share your experience or to ask your doubt. So, whenever you will enter your comment, that comment will be publicly available. Further, if any other user visits the same page i.e., https://xyz.com/article.php he can see the comment at the bottom of the page. This is a normal condition.
But let us think from a hacker’s point of view. What if instead of a valid comment an attacker enters some XSS payload? If the website does not validate input before storing them in its database then the XSS payload will be saved for forever in the database until it is removed by the admin. In this way, the attacker’s XSS payload is injected into the comment section. If this website is vulnerable to Stored XSS vulnerability then anyone visiting this page at https://xyz.com/article.php will definitely get an XSS pop-up. In this way, this is not just affecting a single user but it is affecting all those users who are accessing the vulnerable webpage.
Stored XSS is most commonly seen in
- Forum or Message Board
- Blog comments of any post
- Shopping cart of e-commerce website
- User Profiles Page: the application allows the user to edit/change profile details such as first name, last name, nickname, avatar, picture, address, etc.
- File Manager: application that allows the upload of files
- Application settings or preferences: an application that allows the user to set preferences
- Log: if the application stores some users’ input into logs.
How to Exploit Stored XSS in General
Hacking Steps
These are the general steps that have to be followed every time while testing for stored XSS on any website:
The first step is to identify all points where user input is being stored into the back-end
and then displayed by the application and the remaining steps are similar to reflected XSS i.e.,
- Firstly, input some unique string in the input fields of the website and submit it.
- Open
page source
by right click or by pressingCTRL+U
and search for the unique string in the Page Source. - Use CTRL+F to find the unique string which you have entered in step one. If the unique string reflects back in the browser windows or in the page source then the site may be vulnerable to Stored XSS.
- At last, fire XSS payload viz. <script>alert()</script> and submit it to get a further response in the browser. If the site is vulnerable you will definitely get an alert box.
Now we have learned the basics let us exploit Stored XSS vulnerability in the DVWA web application. First of all login into your DVWA web application by default credential admin
: password
or something other which you have set.
Low Security
We will start from low level and will proceed to high level gradually. Click on DVWA security
on the left pane to change the difficulty to low
.
Select Security Level
to low
and submit
to submit the request. Further, click on XSS (Stored)
on left pane to select the vulnerability to Stored XSS
because we are going to practice Stored XSS attack.
As we can see there are two fields Name
and Message
.
Let us input some unique string
to check whether they are reflecting in the browser window or not. In my case, I have entered test1
& test2
in Name
& Message
field respectively. Then click on Sign Guestbook
to submit the request.
Soon our request is submitted, our next step is to check the page source
whether our unique string is reflecting or not. On pressing CTRL+U
to check page source
and then searching for test
string revealed that test1
and test2
both are reflecting. Since both are reflecting in the browser so both these fields may be vulnerable to Stored XSS attack.
Now our last step is to fire the XSS payload into either of these two input fields. I am using a very basic XSS payload <script>alert()</script>
in Message
field. Click on Sign Guestbook
to submit the message. If this site is vulnerable to stored XSS vulnerability
then we will get a popup when we refresh
this page.
When I refreshed
this same page I got an XSS alert box
. This box confirms that this site is vulnerable to stored XSS attacks.
So we have successfully exploited Stored XSS
at low security
. Now each time we refresh the same page we will get this alert box because our XSS payload is stored in the Guestbook
. If we want to exploit this vulnerability at other security levels we have to first clear the Guestbook
otherwise we will get this alert box again and again. So before proceeding further click on Clear Guestbook
to delete our XSS payload from the guestbook.
Medium Security
Change the security level to Medium
by clicking on DVWA Security
and then choose XSS (Stored)
on the left pane.
We will follow the same steps as we have followed at low level
security. First of all input some unique strings into Name
and Message
field. Then check page source
whether the inputted string is reflecting or not. When I tried to find my unique string in the browser I could easily find both the strings in page source
. So here these fields may be vulnerable to Stored XSS attack. Let us fire our basic XSS payload <script>alert()</script>
into Message
field and then click on Sign Guestbook
to submit the message.
Upon refreshing the page I could not get any pop up
. Why we didn’t get any alert message although we entered a valid XSS payload? There may be chances that the backend code is performing some type of input sanitization or html encoding on the message field when it is accepting the user’s input. Don’t know exactly how message data is being processed in the backend. Let us look at the source code of the server page which is accepting user data.
First block is for performing input sanitization on message
field. This block contains two php functions
for performing input sanitization. First one is strip_tags()
. It removes all html tags from the message field before storing them in database. Second function is htmlspecialchars()
. It converts all the bad characters like &
, "
, '
, >
and <
in their equivalent HTML character encoding
so they won’t remain in their original form when they reflect back
in the browser. You can confirm it by checking the page source
.
So, in message
field there are two levels of sanitization. Firstly strip_tags()
function removes all the HTML tags from the message field and even if some text containing quotes or bad characters passes through this function, htmlspecialchars()
will definitely encode them into equivalent HTML characters. So our XSS payload becomes useless. From here we conclude that the message field is completely secure and we cannot inject any XSS payload into it. This was the reason when we gave <script>alert()</script>
as our input in message field it only showed alert()
text in page source
because strip_tags()
function removed <script>
and </script>
tags from it.
Second block is for performing input sanitization on Name
field. It uses just one function for performing input sanitization. The function is str_replace()
. Here this function is replacing all the occurrences of <script>
tag with null
or blank
character. We can use this field to inject our XSS payload. Since this field is replacing all occurrences of <script>
tag so we cannot use any XSS payload which contains <script>
tag in it.
Bypass
We can bypass this security by using some other payloads which do not contain <script>
tags in it and we can use script tag with different casing enabled. Like we can use <Script>
or <scRiPt>
or <ScRiPt>
in place of <script>
. So our new payload will be something like this <Script>alert(“Hacked”)</Script>
. Let us inject it in Name
field. So when I tried to enter this payload in Name field it does not accept all the characters of our payload because it has some client side restriction
. The restriction is, that a user can enter a maximum of 10
characters in the name field. Since it is a client-side restriction so it can be bypassed very easily.
To bypass the character max length restriction simply open inspect element
by clicking CTRL+SHIFT+C
and take your mouse pointer to Name
field and click on it. Then at the bottom of the windows in source code
double click on maxlength
and change it to 100
from 10
. Press Enter
to apply the changes and close the Inspect window.
Now our maxlength restriction has been removed let us enter our XSS payload. Inject the payload <Script>alert(“Hacked”)</Script>
in the Name
field and in Message
field you can enter anything.
After entering the payload click on Sign Guestbook
to inject the payload and store in the database. Now refresh the page you will get a pop up
showing Hacked
.
We have got alert box
which proves that we have successfully exploited this vulnerability at medium level
difficulty also.
High Security
Let us exploit it at high security. But before changing the security to high level
clear the guest book
and then change the security to high
.
We will follow the same steps as we have followed at low
and medium
security level. First of all input some unique strings into Name
and Message
field. Then check page source
whether the inputted string is reflecting or not. When I tried to find my unique string in the browser I could easily find both the strings in page source
. So here both the fields may be vulnerable to Stored XSS attack
. Let us fire our XSS payload <Script>alert()</Script>
into Message
field and then click on Sign Guestbook
to submit the message.
It did not give me alert message. Let us analyze the source code
of the page which is accepting our input. According to source code block 1
is accepting input of Message
field and performing sanitization on it. Again this code is using strip_tags()
and htmlspecialchars()
functions to sanitize user input as we have seen in medium
security. So there is no chance to inject XSS payload in this field because they will be filtered
by these functions.
Block 2
is for performing input sanitization on Name
field. It uses just one function for performing input sanitization. The function is preg_replace()
. Here this function replaces every occurrences of <script>
tag irrespective of their cases with null
or blank
. So here every XSS payload which includes <script>
tag into it will be useless.
Bypass
To bypass this we have to use some other XSS payload which does not contains <script>
tag into it. There are many number of payloads available to bypass this. I am again using very basic one and the payload is <svg/onload=alert(“Hacked”)>
. This will be injected and won’t be blocked by preg_replace()
function.
So our new payload is <svg/onload=alert(“Hacked”)>
. Let us inject it in Name
field. So when I tried to enter this payload in Name
field it does not accept all the characters because it has some client side restriction. The restriction is that, that a user can enter a maximum of 10 characters. Since it is a client side restriction so it can be bypassed very easily. And the bypassing steps I have already explained in medium security.
After we have bypassed the length restriction, inject the XSS payload in Name
field and in Message
field you can insert anything since it is not vulnerable.
After injecting the payload click on Sign Guestbook
to store the Message
and Name
in the database. Refresh the page you will get popup.
We have got a popup that confirms that we have successfully exploited Stored XSS vulnerability at High-Level Security. So we have successfully exploited Stored XSS vulnerability in DVWA web app at low
, medium
and high
security.
Thanks for reading this article on stored XSS. Hope you have learnt something new from it. For any queries and suggestions feel free to contact us at [email protected].
Update [29/08/2022]
If you are trying to exploit Stored XSS at high-level security on DVWA 1.0.7 [which is present in the default installation of Metasploitable Linux 2] then it is already patched in high-level security. The above payload (or in fact, any other payloads) will not work as of now.
Can strip_tags() and htmlspecialchars() be defeated to Exploit XSS ?
htmlspecialchars() can prevent XSS if properly implemented and till now it is the best way to prevent XSS in php. And we can’t completely rely on strip_tags() for XSS prevention because it can even be bypassed by using JavaScript Pseudo-Protocols, Event-Handlers, etc.