Pentester Academy has a large number of courses and challenges devoted to learning penetration testing and improving your skills.
My aim here will be first to demonstrate basic reflected XSS and then show how 2 different filters can be beaten.
Challenge 16: HTML Injection
The first one we'll look at is challenge 16.
This is the actual challenge page, if you browse to it, you should see this:
What I'm going to do is replace the whole form with one of my own which submit's to a server of my choosing and has an extra field but, otherwise, looks exactly the same as the real 1.
First, let's have a look at the vulnerability. First we need to see what happens when we submit a form:
I submitted the form with
foo in the username field and
bar in the password field. This is the full URL that I end up with:
As you can see, this was just submitted to the same page as a GET request. As this is the case, we can just manipulate this URL to test the fields, if the form had submitted a POST request, we'd have to keep submitting the form or use something like Burp Suite's Repeater feature.
Before that, let's check the source of this page to see in what context on the page our input has landed, right click on the page and click something like View Source:
So we've landed inside the
value attribute of an input tag.
Now let's check if we can use certain characters, send the following URL:
It looks like theres little to no filtering here, we've managed to close the
input tag with the greater than (>) character that we sent, but let's look at the source:
So as suspected, there has been no filtering, this makes our job much easier.
Looking at the source code of the vulnerable form, we can figure out any required prefix and suffix:
1 2 3 4 5 6 7 8 9
All we should need to do here is break out of the
value attribute and the
input tag, to do this we'll need to put a double quote (") (because the value attribute was opened with a ") and >, respectively, at the start of our input.
We should now test for the classic alert box XSS payload with our prefix of
"> by sending the following URL:
It worked, I put the alert statement inside
If you close the alert box and view the source you should see this:
alert('xss'), and as I will demonstrate this allows us full control over the page that is displayed.
The first thing we need to do is remove the current form so that we can put our own form in its place.
We can find all of the forms on the page using the
If you open firebug, go to the Console tab and type document. if will show you a list of its methods and attributes.
If you look through the whole source of the webpage you will see that there is only 1
getElementsByTagName returns an array containing all of the
form objects so to access the actual form we need to run
document.getElementByTagName("form") to access the first element of the array:
Each object has a remove method, we can use this to remove the original
Let's try using the XSS to first remove the
form using the method described and then trigger and alert box as we did before, for this we will use the following URL:
So that didn't work, let's look at the source and see what happened:
So it appears that our payload was cut off from the ;, we can solve this 2 ways, the first is easiest and most well known, replace the ; with a URL encoded version (%3b):
That works, but I also want to show you another method incase ;'s are blocked completely, ;'s can be replaced with comma's (,).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
All of the information here, especially the class names, I got from the original
form. I've created a new form field on line 7 and set its settings on lines 10, 17, 18 and 19.
On line 30, I set the form action to
http://localhost:9000/, this means when the form is submitted it will send the request to
localhost on port
9000, this could be set to any value/server under the attackers control.
form is contained inside the form variable.
The last thing to do is place the form at the right place on the page. If you look through the source, the
form is placed inside a
div tag with the class
container, before a
div tag with a class
1 2 3
Now we have all of the code we want to run, we just need to shrink the code as much as possible, we do this because in any exploit its best to keep the payload as small as possible so there is less chance of it being noticed.
Firstly all of the spaces need to be removed, in most situations spaces only make the code easier to read, next we can shrink all of the variable names down to 1 character, let's just take the first character of each as their name, unless
use strict; is used on the page (which it isn't) there is no need to declare the variables with the
var keyword and lastly we use the
document object repeatedly, we can create a variable with a 1 character name that point to it and use the variable instead (
After applying the rules above, moving everything to 1 line and changing the ;'s with ,'s you get the following code:
1 2 3 4 5 6 7 8 9 10 11 12
We could probably shrink this down some more but this will do for now.
To send this payload we have to send the payload inbetween the
script tags, after that you should see the following:
Looking at the source we can see that it has been injected fine:
Python Capture Server
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
This server is set to print the values to stdout and then redirect to the actual application.
With the above python server running, when our custom form is submitted you get the following:
And the output on the python server's stdout:
1 2 3 4
So that is challenge 16 completed for what we wanted to achieve and everything is transparent to the end user, you just need to send the malicious link to the target.
Challenge 16 Secure
The next challenge is here, some filtering has been added to mitigate the previous exploit.
First let's look at the challenge:
This looks exactly the same as the last challenge, so let's use the application and see if that is the same:
So far everything looks the same, even the URL we are sent to:
Let's analyse this application the same way as before by sending the following URL:
Looks interesting, let's look at the source:
Ideally we want the event handler to run without any interaction, a lot of the event handlers require some interaction.
We are landing inside an
input tag and 1 event we can hook is the
onfocus event, but we need to make sure that the
input box is in focus when the page loads, for this we can use the
So we now need a new prefix for our payload, we need to close the value attribute, with a ", we then need a space and the
autofocus keyword, then a space and lastly
onfocus=", so we end up with:
" autofocus onfocus="
After this there is no need to put any
script tags, we can't anyway because < and > gets encoded.
Let's try executing an alert box to test if XSS works here, we need to send the following URL:
http://pentesteracademylab.appspot.com/lab/webapp/htmli/1/secure?email=" autofocus onfocus="alert('xss')
1 2 3 4 5 6 7 8 9 10 11 12
Sending this in place of
alert('xss') in our previous request gives us the following:
Looking at the source, we can see how our payload got interpreted:
Now we are in the same position as we were when we'd got our custom form on the other page.
Last Challenge: DOM XSS
This is the last challenge I'd like to demonstrate.
Even though this challenge is very different I want to create the same exploit where I create a custom form and put it on the page in a similar position as the previous examples.
Its quite a bit more difficult to exploit but let's get to it and have a look at how it works:
Its clearly doing some maths here based on the value of the
statement argument given in the address bar, let's look at the source:
So we are landing inside
script tags and our input is being used as an argument to
This time, however, we can't see how our payload is being interpreted directly.
So the problem is that the ' are URL encoded... This is because, as you can see from the source code, it is accessing the argument using the
document.URL property where certain characters are URL encoded so we will be unable to use any types of quotes (' or ").
There are probably a few ways to beat this problem, an obvious 1 is to avoid using strings but we are unable to do that here.
Let's try to execute an alert using this method, we need to send the following URL:
We will be using the
substring methods a lot, so it would be best if we create aliases for these to shorten our payload, we can create a function for the
substring section like this:
I have used /**/ here because we are also unable to use spaces (they are URL encoded too) and this just acts as a comment.
This function takes 1 argument and returns the string with the first and last character removed.
We can create an alias for the
String method using this code:
Before we start to write our payload, let's test this with an alert by sending the following URL:
So it works, lastly all we need to do is remove the string
Mathemagic and the
div tag that contains the result.
Looking at the source we can see that the
Mathemagic string is contained in a
h2 tag and there are no other
h2 tags on the page, so we can find this using the
The result is contained inside a
div tag which has the
id value set to
result, so we can find this using the
Both of these we can remove using the
We are now ready to write our payload, here is the "beutified" version of the payload, remember that this all goes on 1 line and with , seperating the instructions and not ;:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
So using this the URL that you will need to send is:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
After sending this URL you should see the following:
For the last to exploits, the redirection URL of the python server would have to be changed.
There are various methods for bypassing different filters and I've only mentioned a couple here but the methods that you use will highly depend on the filter that you are facing.
A lot of trial and error is needed to determine how best to bypass the filter than is in place.
In each of these examples, to take advantage of the exploit, you need to send the URL that we have created to the victim. A URL containing all of this information might look very strange to the victim so it might be best to URL encode the whole payload, you can do this in BurpSuite's Decoder tab or on a website like this, its worth noting though that Burp will URL encode all of the text (incuding any alphanumeric characters), that website (like most) will only encode certain characters.
OWASP is the authority on web security so their website contains any relavent information regarding this.