You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Like we talked via email, I'm posting here the details and the Proof of Concept of my research. I've been mainly testing on Brave, but this also affects the Firefox version.
In the current version of the extension, the above line is responsible for detecting all the URLs that contain //, unless the ;base64, value is found. This would indicate the content is base64 encoded, e.g.: url(data:image/png;base64,iVBORw0KGgoAAAANSU+h//EUgAAAaQAAA/GkCAYAAAB+TFE). In this case, the extension will ignore such rule.
The problem lies in not enforcing a strict matching of the ;base64, at the beginning of the url(). Thus, it's possible to craft a non base64 encoded URL by inserting this value as either an URL fragment, like http://url/pwned1.png#;base64,, or even as a filename, since the special characters ; and , are valid within an URL and within a filename, so http://url/;base64,pwned11.png.
The proposed fix I've found is changing the conditions to a stricter match, so:
CSS variables allow to split the CSS selector and the url() value in two different CSS Style Rules. In the context of this extension, the checks happen only for CSS selectors and url() in the same CSSStyleRule, so using CSS variables would allow for a bypass. E.g.:
Lastly, the above condition checks if the CSS Rule has any selectorText property, otherwise there is nothing to filter. This works for CSSStyleRule but not for others like CSSSupportsRule or CSSMediaRule, which in turn contain one or more CSSStyleRule and have no selectorText.
This means we would need to iterate through all the nesting, if present, in order to extract all the CSSStyleRule, which are the ones we need instead.
I put together the following fix. First, I've created a function which takes care of recursively extracting all the style rules:
functionextractStyleRule(_obj){letrules=[];if(Object.prototype.toString.call(_obj)!="[object CSSStyleRule]"&&_obj.cssRules!=undefined// keyframes have no cssRules){for(leti=0;i<_obj.cssRules.length;i++){rules=rules.concat(extractStyleRule(_obj.cssRules[i]));}}else{rules.push(_obj);}returnrules;}
And then I've edited the beginning of parseCSSRules() before looping through all the selectors:
varselectors=[];varselectorcss=[];trules=[];if(rules!=null){for(i=0;i<rules.length;i++){if(Object.prototype.toString.call(rules[i])!="[object CSSStyleRule]"){varextracted_rules=extractStyleRule(rules[i]);//rules.splice(i,1);trules=trules.concat(extracted_rules);}else{trules.push(rules[i]);}}rules=trules;// or rename rules[0] to trules[0] everywhere in the function
I've haven't had a lot of time to work on a full implementation of the fix for the case based on CSS variables. Instead, I can confirm that the other two proposed fixes do work, though I'm open to any feedback for improvement. 🙂
PoC screenshot:
The text was updated successfully, but these errors were encountered:
Hey Mike,
Like we talked via email, I'm posting here the details and the Proof of Concept of my research. I've been mainly testing on Brave, but this also affects the Firefox version.
Test Page: https://randshell.github.io/CSS-Exfil-Protection-POC/
Repo: https://github.com/randshell/CSS-Exfil-Protection-POC
Issue 1:
CSS-Exfil-Protection/chrome/content.js
Line 242 in d0ad3ae
In the current version of the extension, the above line is responsible for detecting all the URLs that contain
//
, unless the;base64,
value is found. This would indicate the content is base64 encoded, e.g.:url(data:image/png;base64,iVBORw0KGgoAAAANSU+h//EUgAAAaQAAA/GkCAYAAAB+TFE)
. In this case, the extension will ignore such rule.The problem lies in not enforcing a strict matching of the
;base64,
at the beginning of theurl()
. Thus, it's possible to craft a non base64 encoded URL by inserting this value as either an URL fragment, likehttp://url/pwned1.png#;base64,
, or even as a filename, since the special characters;
and,
are valid within an URL and within a filename, sohttp://url/;base64,pwned11.png
.The proposed fix I've found is changing the conditions to a stricter match, so:
Issue 2:
CSS variables allow to split the CSS selector and the
url()
value in two different CSS Style Rules. In the context of this extension, the checks happen only for CSS selectors andurl()
in the sameCSSStyleRule
, so using CSS variables would allow for a bypass. E.g.:Another similar way to insert a malicious URL is through CSS fallback values:
Issue 3:
CSS-Exfil-Protection/chrome/content.js
Line 236 in d0ad3ae
Lastly, the above condition checks if the CSS Rule has any
selectorText
property, otherwise there is nothing to filter. This works forCSSStyleRule
but not for others likeCSSSupportsRule
orCSSMediaRule
, which in turn contain one or moreCSSStyleRule
and have noselectorText
.E.g.
In fact, these rules can also be nested multiple times, like for example:
This means we would need to iterate through all the nesting, if present, in order to extract all the
CSSStyleRule
, which are the ones we need instead.I put together the following fix. First, I've created a function which takes care of recursively extracting all the style rules:
And then I've edited the beginning of
parseCSSRules()
before looping through all the selectors:I've haven't had a lot of time to work on a full implementation of the fix for the case based on CSS variables. Instead, I can confirm that the other two proposed fixes do work, though I'm open to any feedback for improvement. 🙂
PoC screenshot:
The text was updated successfully, but these errors were encountered: