Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
I recently came across a challenging frameset xss, and I wanted to sure how I was able to exploit it.
First, imagine the following application.
root@kali:~/frameset# cat frameset.php <html> <head> <title>Vulnerable Frameset Example</title> </head> <frameset cols=21%,* framespacing=1> <frame name=left src="left.html" frameborder=1 framespacing=0> <frame name=right src="<?php echo $_GET['right'] ?>" frameborder=0 framespacing=0> </frameset> <body> Can't see me </body> </html> root@kali:~/frameset# cat left.html I'm the left frame! root@kali:~/frameset# cat right.html And I'm the right frame?
If we visit the page, we get the following view.
To start, this is a simple, but to the point application. We can verify that PHP is using the GET parameter by inputting an invalid one.
As the application is writing directly into a tag, we could just escape the current tag, and placing a script tag.
To verify that we can write arbitrary HTML, we can send a test tag.
Unfortunately, if we look into the source of the page and Firefox’s debugger, we see the first sign of trouble.
For those of you not aware, the frameset tag is a wonderful tag, and one of the few in HTML that actually cares what is around it. For starters, if you have a frameset tag, your HTML document cannot have a body. Additionally, the only tags allowed inside of a frameset are “frame” and “noframes”, that is it.
To verify that our first idea wouldn’t work, we can try exiting the frame tag and creating a script tag. As you can see, the debugger gives us an error and we do not receive an alert.
Option one to solve this problem, is to use our XSS polyglot. If we use this as a new frame src, then the page will load the HTML into the frame, and our script will fire off.
To verify this, I finished the current frame tag, and created a new one. As you can see, the frameset XSS fired off!
The source of the page verified that there we no longer any errors, and that we had a new frame with the source of our XSS domain.
Unfortunately, this attack option does come with a downside.
If we add the following code to our application, it will also have a “secret” cookie value.
<?php $cookie_name = "secret"; $cookie_value = "thisISmy$3cr3t"; setcookie($cookie_name, $cookie_value, time() + (86400 * 30), "/"); // 86400 = 1 day ?>
We can verify that the application sets the cookie by running alert(document.cookie) in the browser console.
Unfortunately, if we attempt to get access to the cookie from our XSS payload on r4y.pw, we are unable to get to it. The reason for this is that we are violating the Same-origin policy. As we are loading our payload externally into a frame, it is coming from r4y.pw directly instead of the local application. In this case, we would not be able to steal a user’s cookies or session.
Unfortunately, since option one doesn’t bypass the SOP, we’ll have to move on to option two.
As we can create new frames, we can use a JavaScript URI, and code our payload inline.
For example:
right.html" frameborder=1 framespacing=0><frame src="javascript:alert(1)
After we load the page, we get our alert to fire off.
As this is local JavaScript, we no longer have to worry about violating the SOP, and could use this to grab cookies.
If we can’t, or don’t, want to use a JavaScript URI, then there is still another option for us!
Since we are able to write arbitrary frame tags, we can use a data URI and write arbitrary JavaScript as our frame src.
For example, we can use the following payload.
right.html" frameborder=1 framespacing=0><frame src="data:text/html,<script type='text/javascript'>with(parent) {alert('xss');}</script>
Once we load the page, we can verify that our alert fired off!
Additionally, inside the source of the page, we can see our newly created frame.
The main benefit of this payload over option one, is that the local application is loading the script, thereby bypassing the SOP.
Next, we can use the following payload.
right=right.html" frameborder=1 framespacing=0><frame src="data:text/html,<script type='text/javascript'>with(parent) {alert(document.cookie);}</script>
When we view the source of the page, we can see that our payload and HTML is still intact.
Finally, when we load the page, our frameset XSS fires off and we can steal the user’s cookie!
Ray Doyle is an avid pentester/security enthusiast/beer connoisseur who has worked in IT for almost 16 years now. From building machines and the software on them, to breaking into them and tearing it all down; he’s done it all. To show for it, he has obtained an OSCE, OSCP, eCPPT, GXPN, eWPT, eWPTX, SLAE, eMAPT, Security+, ICAgile CP, ITIL v3 Foundation, and even a sabermetrics certification!
He currently serves as a Senior Staff Adversarial Engineer for Avalara, and his previous position was a Principal Penetration Testing Consultant for Secureworks.
This page contains links to products that I may receive compensation from at no additional cost to you. View my Affiliate Disclosure page here. As an Amazon Associate, I earn from qualifying purchases.