XSS is art

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)

15 Responses to “XSS is art”

  1. thornmaker writes:

    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!

  2. thornmaker writes:

    default xml namespace=toolbar,x=’loca’
    default xml namespace=toolbar,this[x+’tion’]=name

  3. Gareth Heyes writes:

    That’s pretty damn good, I tried to inject strings using + but I always hit the centrifuge. Nice1!

  4. Gareth Heyes writes:

    This has now been fixed, the final payload can be viewed here:-

    http://www.businessinfo.co.uk/labs/phpids/phpids3.html

  5. Gilzow writes:

    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?

  6. Gareth Heyes writes:

    @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.

  7. Gilzow writes:

    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…

  8. Gareth Heyes writes:

    Yeah that’s because Mario already fixed it πŸ˜‰

    Here’s a demo of how it did work:-
    demo

  9. Gilzow writes:

    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.

  10. DoctorDan writes:

    Oh, you tricky, tricky man.
    XSS is art, and in this case is certainly beauty as well πŸ˜›

  11. Erik writes:

    i think xss it’s art too :xD

  12. Spletno gostovanje writes:

    XSS… it really is an art…

    I agree πŸ™‚

  13. thornmaker writes:

    The opera trick you showed me earlier today also works in FF3 provided you use eval:

    ‘xalert(0)x’.replace(/a……./,eval)

  14. Gareth Heyes writes:

    Nice! πŸ™‚

    Can be shortened too
    ‘xalert(0)x’.replace(/[^x]+/,eval)

  15. thornmaker writes:

    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?