webRequest.filterResponseData allows extensions to bypass the Content Security Policy and execute remote code
Categories
(WebExtensions :: Request Handling, defect)
Tracking
(Not tracked)
People
(Reporter: robwu, Unassigned)
References
Details
Attachments
(1 file)
1.01 KB,
application/zip
|
Details |
I was investigating the recent spike in reported crashes of bug 1403546, and came across several unlisted extensions. I analyzed a XPI that Andreas shared. The code is heavily obfuscated, but I managed to reverse engineer the logic and identify a security vulnerability in Firefox that allows unexpected remote code execution in the context of an extension page.
The vulnerability is the result of combining CSP relaxation with the webRequest.filterResponseData
API.
The webRequest.filterResponseData
API allows extensions to modify response bodies of requests.
The Content Security Policy is used to prevent extensions from executing remote code in privileged extension pages (e.g. background pages). The CSP defaults to the equivalent of script-src 'self'
. Extensions can relax the policy via the content_security_policy
field in manifest.json, and allow remote code via unsafe-eval
or a https:-URL.
When unsafe-eval
is used, it is quite clear that an extension may be executing remote code.
When a https:-URL is used, the expectation is that the extension may load a resource from that URL. If the URL is a well-known CDN, then a reviewer could mistakenly believe that the extension does not execute arbitrary code.
I will attach a test case in the next comment.
Reporter | ||
Comment 1•6 years ago
|
||
str |
STR:
- Load attached extension.
Expected:
- No tab opens. The console of the background page (available via the "Debug" button at
about:debugging
) should show:SyntaxError: expected expression, got '<'
Actual:
- A tab opens. This demonstrates that the extension was able to intercept the response to a https URL and replace it with arbitrary content. The content opens the test script itself in a new tab as a demonstration.
Reporter | ||
Comment 2•6 years ago
|
||
Cc-ing AMO admins for awareness.
Comment 3•6 years ago
|
||
This is expected
Reporter | ||
Comment 4•6 years ago
|
||
The behavior of the individual APIs are expected, but the consequences of the combination are not. Or at least, not desired.
When a well-known HTTPS URL is whitelisted, e.g. via
"content_security_policy": "script-src https://ajax.googleapis.com/; object-src 'none';'
... then the expectation is that the extension only allows scripts from ajax.googleapis.com. Not that they can execute arbitrary scripts. In contrast, when 'unsafe-eval'
is used, then it is obvious that an extension may run remote code.
I would expect the webRequest.filterResponseData
to ignore script requests from extension origins to mitigate this issue.
There is already precedent for blocking undesired behavior, e.g. preventing the webRequest
API from intercepting extension-initiated synchronous XHR.
Comment 5•6 years ago
|
||
It is both expected and desired.
Reporter | ||
Comment 6•6 years ago
•
|
||
Do you read past the first line of my comments? If you did, could you challenge the specific points that I make instead of giving few-word comments without context?
I claim that bypassing the content security policy via the webRequest
API allows for unexpected remote code execution, which is a security risk.
There is no legitimate reason for allowing arbitrary strings to execute as privileged code. It makes auditing for malicious beheavior harder too. Without this vulnerability, privileged code execution is far more obvious:
- The
content_security_policy
would include'unsafe-eval'
, or - The
content_security_policy
would include an obscure https:-origin and the extension loads a https:-URL in a script tag, that clearly is not a standard library.
Comment 7•6 years ago
|
||
(Reopening pending more details)
Reporter | ||
Comment 8•6 years ago
|
||
Kris has elaborated on his stance in IRC:
Because that's just the way stream filters work. If you have permission for a site, you can generate and change data as if you were that site. The same sort of behavior could be achieved by running a script on the site that let you send it data and then returned that data when you tried to load a script from it.
Basically, if your CSP allows running remote scripts, you're opting into running dynamically-generated scripts.
The CSP does explicitly allow it. It allows executing scripts from googleapis.com. The extension's host permissions allow it to speak for googleapis.com. Ergo, it explicitly allows it.
Though, strictly speaking, AMO shouldn't be accepting any add-ons with CSPs that allow remote scripts. That's been against policy for years.
This expectation makes sense when all remote resources are viewed as equally untrustworthy.
I previously assumed that there would be a difference between well-known hosts and obscure origins.
However, the AMO admins said that both are viewed as equally untrustworthy, so there is no point in putting effort into blocking modifications of script subresources in extension pages.
Updated•5 years ago
|
Description
•