XSS is art
Published 17 years ago
Published: Thu, 11 Sep 2008 20:37:52 GMT
Updated: Sat, 22 Mar 2025 15:38:11 GMT
Read time: ⏱️ 3 min read
I had a bet with a friend of mine David Lindsey aka Thornmaker. Basically we said the first one to get a XSS vector on phpids buys a beer at Bluehat :) I haven't had much time to do this because I've been pretty busy but over the last few days in my spare time I've been slowly constructing a vector. David you owe me a beer :D
What is interesting about phpids is that it includes a centrifuge detection system which compares past vectors and known good inputs which enables them to detect future attacks that slip past their regular expressions. The system has greatly improved since the early days and I actually had a ton of XSS vectors which got past their expressions but not centrifuge.
So in my crazy world of XSS how can you bypass a protection like this? Well in Firefox there's a E4X statement which I posted previously that doesn't look like javascript syntax. e.g. :-
<pre lang="javascript"> default xml namespace = statement </pre>Using this method I managed to construct my vector which used this to bypass centrifuge but I had a problem, how to first get a payload and how to call that payload. Why is that a problem? Because phpids checks common injections like eval, alert etc.
I decided to try various different tricks using "this" which refers to the current window in javascript when executing from a script tag in Firefox. The methods I used worked well but the centrifuge detection was triggered when using "+" to concatenate strings.
Simple calls to 'abc'.concat('def') were blocked quite easily so I needed another method. Using a && trick to bypass some of their regular expressions it was possible to call a global function by assigning it to a variable:-
<pre lang="javascript"> default xml namespace=toolbar,b=1&&this.atob </pre>So the default xml namespace bypasses centrifuge and the variable b is assigned to the atob function in Firefox. This is because in javascript the right side of the statement is returned not 1 when using && in this context. I could get the string eval by converting base64 and convert the string to a function using the techniques described.
All I needed now was the payload and that was obtained using the 1&& method but this time using window.name:-
<pre lang="javascript"> default xml namespace=toolbar,y=1&&name </pre>I had all the raw ingredients now to finish my vector which produced the final vector that looks like a work of art to me :)
<pre lang="javascript"> default xml namespace=toolbar,b=1&&this.atob default xml namespace=toolbar,e2=b('ZXZhbA') default xml namespace=toolbar,e=this[toolbar,e2] default xml namespace=toolbar,y=1&&name default xml namespace=toolbar default xml namespace=e(y) </pre>