Security: Shared event loops leak information
Reported by
pvtolk...@gmail.com,
Nov 18 2016
|
|||||||||||||
Issue description
I'm not sure if I should have filled a "privacy issue" or just posted on the "security-dev" list, so apologies if I'm wrong.
VULNERABILITY DETAILS
I would like to discuss a timing side channel on shared event loops in Chrome. The issue is probably well known, but some results indicate that it can lead to some practical attacks.
VERSION
Chrome Version: Stable (most recent versions)
Operating System: Tested on Linux and OSX
REPRODUCTION CASE
The problem arises when an event loop is shared among parties from different origins. By recursively posting tasks into a loop and measuring the time at when each is processed, one party A can detect V's tasks:
Loop pipeline: [ A ] [ A ] [ A ] [ V ] [ A ] ...
^ ^ ^ ^
t1 t2 t3 t4
In this example, A can infer how long V's task takes: t4-t3.
Using this idea I'm able to spy on the MainThread's message loop of renderers with a resolution of ~25 microseconds, from a simple HTML page:
<script>
function loop() {
save(performance.now());
self.postMessage(0,'*');
}
self.onmessage = loop;
self.postMessage(0,'*’);
</script>
Or to spy on the I/O thread of the host (or browser) process with a resolution of less than 0.2 milliseconds:
<script>
function loop() {
save(performance.now());
fetch(new Request('http://0.0.0.0')).catch(loop);
}
loop();
</script>
These resolutions depend on the machine, but in general are quite high. Note also that the are other ways to post async tasks apart from the postMessage or Fetch APIs (e.g., the demo below uses SharedWorkers).
Here you can find two PoCs:
- Simple covert-channel across processes: https://www.youtube.com/watch?v=IlndCZmRDmI
- Tool for visualizing the load on the host's IO event loop: http://vwzq.net/lab/ioloop/monitor.html
You can monitor the loop and see the effect of opening a page in a new tab (for reducing noise run it on a separate Chrome instance) and navigating on it.
The timing measurements allow to fingerprint web pages with some basic machine learning techniques, and to visually recognize user actions (like mouse movement, scrolling, clicks or even keystrokes) in cross-origin tabs.
I'm really interested in whether you consider this as a potential threat, if you are already working on some mitigation (like SiteIsolation for the renderer's case or some scheduling policies), or if it's just a "won't fix".
Thanks :)
,
Nov 19 2016
Yes, I only see delays introduced by events, rendering, GPU messages, GC, network requests, etc., potentially produced by an unknown origin. However, in the case of sharing the renderer it is possible to know the other origin, and the timing patterns (duration/around/frequency) of events with no JS listener are more or less distinguishable. Each event triggers a different cascade of layout/rendering actions that translates into specific sequences of delays in the message loop. Also, if an origin V has some JS listener, then the timing pattern (or sequence of delays) will be specific to V and we can learn it previously. Automating this is not easy, since we need some "online learning phase", but I think it is possible. As for detecting pages in new tabs, the event loops are usually "quiet" when all pages are already loaded (it may depend on the background work), but when a new page is visited a bunch of network requests and rendering tasks are executed, producing a clear pattern (see graph attached) recognizable by the human eye and by classification techniques. This is what can be seen in the second demo: start monitoring, open new tab, visit page X, stop monitoring. A graphic will be painted with X's loading pattern. The video was just an example of a covert-channel between 2 cooperative pages from different origins and in different processes. I use timing delays introduced in the I/O thread to transmit the "hello!" message as 0s and 1s. Sorry if I was not clear enough.
,
Nov 26 2016
Thank you for providing more feedback. Adding requester "palmer@chromium.org" for another review and adding "Needs-Review" label for tracking. For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
,
Nov 27 2016
,
Nov 28 2016
,
Nov 28 2016
How can origin A (say, attacker.com) reliably know the identity of origin B (say, example.org), due only to the fact that they share a renderer? Origin A would need to have compromised the process (e.g. by exploiting a memory corruption bug), right? If you have some other means of achieving that, I think that would be a bug on its own. Or did you mean just by classifying the event timing patterns? I'd be somewhat surprised if it were practical for an attacker to classify the event timings of the origin B whose users they want to spy on, for all combinations of origin B state and for all combinations of origin B running together with origins C, D, ... . +lcamtuf: Potentially of Silence On The Wire interest. It seems to me that some of the attacks described there, such as distinguishing keystrokes by sound (which admittedly is harder for origin A to do, since it would need to request getUserMedia permission), would be easier to achieve in practice. But I could be wrong. +battre: Do you or someone on Privacy Team want to take this?
,
Nov 28 2016
Right now two origins share the renderer when: a) using iframes, b) doing a renderer-initiated navigation, or c) the max number of renderers is exceed. An attacker can use a) and b) for knowing the origin of B and spy on it. It's also interesting that when c), all new incognito-tabs share the same renderer. As an example, an evil advertisment iframed in B has no access to the parent page due to the SOP but may know the origin B thanks to the referer and spy on what the user is doing. Another scenario could be a rogue page that pop-ups Google's OAuth login form and detects the keystrokes: http://vwzq.net/lab/messageloop/monitor_goauth.html This is a very dumb PoC failing a lot, but you can see the idea.
,
Nov 30 2016
,
Dec 1 2016
,
Feb 13 2017
,
Feb 13 2017
,
Mar 13 2017
Hi! Just to keep you in the "loop" ;D Here's a draft of the paper I've been working on: http://vwzq.net/papers/loophole.pdf If you are interested, it contains more detailed info and some experimental results. Interestingly, the CPU throttling mechanism introduced recently in Chrome broke the test case for spying on the renderer from a background tab (though it can probably be bypassed?), but the rest of the scenarios still work. You can now use this http://vwzq.net/lab/loopscan/ to visually inspect the event loops, since the links above are dead. At some point I'll try to add support for the GPU process as well. Again, any comment/feedback is very appreciated. Thanks.
,
Mar 13 2017
,
Mar 13 2017
,
Mar 13 2017
I still don't see a compelling attack, in the demo or in the paper. For things like detecting what sites the person has browsed or is browsing, there already exist more reliable attacks that don't require resource-intensive statistical characterization. (See e.g. https://diracdeltas.github.io/sniffly/) I still don't see a keystroke theft attack, which I really would find compelling. Other side channels are more likely to result in that, e.g. microphone and accelerometer, but those sensors are guarded by permissions or other use restrictions. And there are plenty of other, higher-bandwidth and higher-reliability ways for origins to communicate with each other without the person using the browser knowing. I'm afraid I just don't see an actionable bug here.
,
Jun 20 2017
This bug has been closed for more than 14 weeks. Removing security view restrictions. For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot |
|||||||||||||
►
Sign in to add a comment |
|||||||||||||
Comment 1 by palmer@chromium.org
, Nov 18 2016Labels: Needs-Feedback