Conceal XSS Injection in HTML5
history.pushState() was introduced in HTML5 and it’s meant for modifying history entries.
By using pushState() we’re allowed to alter the visible URL in address bar without reloading the document itself
The Harmful Part : -
The harmful part is that we can conceal the real location and replace it with anything we want. Although the hostname can’t be replaced, we can completely change the pathname.
so, I made a brief PoC about hiding a non-persistent XSS exploit. It’s about executing a malicious script on a login page through a non-validated query parameter (quite common situation). The script redefines form.action and then removes the malicious query parameters of the URL shown in address bar.
Proof of Concept : -
This PoC works only in modern browsers that has implemented this HTML5 proposal. This only works in Google Chrome 9 and Firefox 4 Beta.
pushState() works properly also in Safari 5, but it’s security control refuses to load external scripts or execute injected scripts.
I’ll inject some malicious code via query parameter:
Code:
?username=”>
As you can see the URL is pretty ugly. Therefore shortened it in a trusted URL shortener service (like everyone does nowadays): http://bit.ly/pushStateXSS.
Just visit this URL to see how pushState() behaves and what is shown in address bar.
Conclusion : -
Can this be considered as a security flaw?
Definitely yes.
How it should be fixed? –
There should be a property, eg. history.allowPushState which would be set to false by default. And website developers could explicitly set it to true while being aware of the risks. Edit: I’ve received some feedback about this.
And you’re right – this wouldn’t fix anything since it could be set to true in injection.
By using pushState() we’re allowed to alter the visible URL in address bar without reloading the document itself
The Harmful Part : -
The harmful part is that we can conceal the real location and replace it with anything we want. Although the hostname can’t be replaced, we can completely change the pathname.
so, I made a brief PoC about hiding a non-persistent XSS exploit. It’s about executing a malicious script on a login page through a non-validated query parameter (quite common situation). The script redefines form.action and then removes the malicious query parameters of the URL shown in address bar.
Proof of Concept : -
This PoC works only in modern browsers that has implemented this HTML5 proposal. This only works in Google Chrome 9 and Firefox 4 Beta.
pushState() works properly also in Safari 5, but it’s security control refuses to load external scripts or execute injected scripts.
I’ll inject some malicious code via query parameter:
Code:
?username=”>
As you can see the URL is pretty ugly. Therefore shortened it in a trusted URL shortener service (like everyone does nowadays): http://bit.ly/pushStateXSS.
Just visit this URL to see how pushState() behaves and what is shown in address bar.
Conclusion : -
Can this be considered as a security flaw?
Definitely yes.
How it should be fixed? –
There should be a property, eg. history.allowPushState which would be set to false by default. And website developers could explicitly set it to true while being aware of the risks. Edit: I’ve received some feedback about this.
And you’re right – this wouldn’t fix anything since it could be set to true in injection.
Commentaires
Enregistrer un commentaire