A simple JavaScript injection like this
or even
, usually manages to pop up a vulnerable page warning box when input reflection occurs inside a script block and HTML injection is not possible.
But there are cases where the point of injection is in the middle of more complex JS code: inside functions and conditions (if or if+else) nested inside each other. Let's look at an example of such an injection, step by step.
It will be easy for you to do this with user interaction, but things can get tricky if you don't have JS skills. So we have our next reflection point. It's in the middle of some JS code (keyword=aaaaa).
We then try to do a simple JS injection, but it is escaped with a backslash before each double quote.
As we know from Basic XSS Examples (Example #7), the next trick is to add a backslash before our first quote to "prevent the preempt". You also need to comment out the rest of the line.
This works if we change (via user interaction) the select element on the page.
But there is a better way to do this, since this "feature" will not be available in all cases, and it also requires user interaction.
The plan is as follows: we will close all nested function conditions, and then paste our code (confirm1). We then need to fix the rest of the syntax to be able to run our payload, as the entire script block will fail if there is any syntax error in it.
We start our new attempt with \”}})}) , which are the last 3 lines of our code snippet (no semicolons) to close the “if ”, the “on+change” function, and the “document.ready” function. The rest remains the same as in the previous attempt.
Of course this doesn't work since only half of the payload building is done (the easiest part). But the errors returned in the JS console (press F12 in the browser developer tools) will help us figure it out.
By clicking on the link on the right side of the message, we will find the problem.
The error occurs on the "else" line because it shouldn't be there. We have already closed the if statement along with two functions, so we need to get rid of it.
In this particular case, we are dealing with a double reflection, so we will try to bring them together so that they become one by opening the comment in the first reflection and closing it in the second. This will be enough to get rid of the code between these two reflections: the "else" line and the "document.location" attribution.
Multiline comments in JS are denoted by /* and */, so a simple /* / at the end will do the job (it parses as /* in the 1st reflection and as */ in the 2nd).
Let's check what this error can mean.
As we can see, the end of the first reflection to the end of the second is now displayed in green. So at the end of our confirm1, the code continues with &pageIndex=1&startFrom=0, which is interpreted as a bitwise AND (&) operator with an invalid variable assignment (pageIndex = 1).
This can be simply solved by commenting out the rest of the line with // appended to the end of the current payload. As a result, we get (with the addition of a semicolon):
Now everything is as expected, all the code after our entered semicolon and up to the closing "}" from the "if" statement is commented out. So let's add "{" to the end of our payload, right before the comment.
Bingo, the parser moved to the next line with an error in the next close!
So let's continue trying to fix the "})" by opening a new one with the content "({" before the "{" to keep the syntax.
What happened? Due to the newly added "({", now our first "{" stops working as a "fix" for the "if" statement. Let's go back to experimenting with adding "if ()" between "( {" and "{".
Great, we are now on the last line! We just repeat what we did in the previous step, adding another "({" right after the semicolon and before "({ if () {".
What did we mess up this time? This has happened before, we just broke the previous "fix". To fix this, let's add "function()" between the newly added "(" and "{".
Cool, we just figured it out! Now we will reduce our payload.
We remove the semicolon (causing the parser to throw an "unexplained error" but still run) and replace "if()" with the label "b:" and "function ()" with the arrow function parameter "a =>" . The names "a" and "b" are completely arbitrary.
The complete JS block looks like the one shown above. Mission accomplished.
Code:
‘-alert(1)-’
Code:
\’-alert(1)//
But there are cases where the point of injection is in the middle of more complex JS code: inside functions and conditions (if or if+else) nested inside each other. Let's look at an example of such an injection, step by step.
It will be easy for you to do this with user interaction, but things can get tricky if you don't have JS skills. So we have our next reflection point. It's in the middle of some JS code (keyword=aaaaa).
We then try to do a simple JS injection, but it is escaped with a backslash before each double quote.
Code:
Payload: “-confirm1-”
As we know from Basic XSS Examples (Example #7), the next trick is to add a backslash before our first quote to "prevent the preempt". You also need to comment out the rest of the line.
Code:
Payload: \”-confirm1//
This works if we change (via user interaction) the select element on the page.
But there is a better way to do this, since this "feature" will not be available in all cases, and it also requires user interaction.
The plan is as follows: we will close all nested function conditions, and then paste our code (confirm1). We then need to fix the rest of the syntax to be able to run our payload, as the entire script block will fail if there is any syntax error in it.
We start our new attempt with \”}})}) , which are the last 3 lines of our code snippet (no semicolons) to close the “if ”, the “on+change” function, and the “document.ready” function. The rest remains the same as in the previous attempt.
Code:
Payload: \”}})})-confirm1//
Of course this doesn't work since only half of the payload building is done (the easiest part). But the errors returned in the JS console (press F12 in the browser developer tools) will help us figure it out.
By clicking on the link on the right side of the message, we will find the problem.
The error occurs on the "else" line because it shouldn't be there. We have already closed the if statement along with two functions, so we need to get rid of it.
In this particular case, we are dealing with a double reflection, so we will try to bring them together so that they become one by opening the comment in the first reflection and closing it in the second. This will be enough to get rid of the code between these two reflections: the "else" line and the "document.location" attribution.
Multiline comments in JS are denoted by /* and */, so a simple /* / at the end will do the job (it parses as /* in the 1st reflection and as */ in the 2nd).
Code:
Payload: \”}})})-confirm1/*/
Code:
Let's check what this error can mean.
As we can see, the end of the first reflection to the end of the second is now displayed in green. So at the end of our confirm1, the code continues with &pageIndex=1&startFrom=0, which is interpreted as a bitwise AND (&) operator with an invalid variable assignment (pageIndex = 1).
This can be simply solved by commenting out the rest of the line with // appended to the end of the current payload. As a result, we get (with the addition of a semicolon):
Code:
Payload: \”}})})-confirm1;/*///
Now everything is as expected, all the code after our entered semicolon and up to the closing "}" from the "if" statement is commented out. So let's add "{" to the end of our payload, right before the comment.
Code:
Payload: \”}})})-confirm1;{/*///
Bingo, the parser moved to the next line with an error in the next close!
So let's continue trying to fix the "})" by opening a new one with the content "({" before the "{" to keep the syntax.
Code:
Payload: \”}})})-confirm1;({{/*///
What happened? Due to the newly added "({", now our first "{" stops working as a "fix" for the "if" statement. Let's go back to experimenting with adding "if ()" between "( {" and "{".
Code:
Payload: \”}})})-confirm1;({if(){/*///
Great, we are now on the last line! We just repeat what we did in the previous step, adding another "({" right after the semicolon and before "({ if () {".
Code:
Payload: \”}})})-confirm1;({({if(){/*///
Code:
What did we mess up this time? This has happened before, we just broke the previous "fix". To fix this, let's add "function()" between the newly added "(" and "{".
Code:
Payload: \”}})})-confirm1;(function(){({if(){/*///
Cool, we just figured it out! Now we will reduce our payload.
We remove the semicolon (causing the parser to throw an "unexplained error" but still run) and replace "if()" with the label "b:" and "function ()" with the arrow function parameter "a =>" . The names "a" and "b" are completely arbitrary.
Code:
Final Payload: \”}})})-confirm1(a=>{({b:{/*///
The complete JS block looks like the one shown above. Mission accomplished.