Electrum: Password protect the JSONRPC interface

Created on 25 Nov 2017  路  75Comments  路  Source: spesmilo/electrum

The JSONRPC interface is currently completely unprotected, I believe it should be a priority to add at least some form of password protection.

Scans for the JSONRPC interface of Ethereum wallets have already started:
https://www.bleepingcomputer.com/news/security/theres-some-intense-web-scans-going-on-for-bitcoin-and-ethereum-wallets/

bug 馃悶 security 馃攼

Most helpful comment

Hello, I'm not a bitcoin user, a colleague pointed me at this bug report because localhost RPC servers drive me crazy 馃槢.

I installed Electrum to look, and I'm confused why this isn't being treated as a critical and urgent vulnerability? If this bug wasn't already open for months, I would have reported this as a vulnerability, but maybe I misunderstand something.

The JSON RPC server is enabled by default, it does use a random port but a website can simply scan for the right port in seconds.

I made you a demo. It's very basic, but you get the idea.

If you did set a password, some misdirection is required, but it's still game over, no?

Here is how I reproduced:

  • Install Electrum 3.0.3 on Windows.
  • Create a new wallet, all default settings. I left the wallet password blank - the default setting.
  • Visit in Chrome.
  • Wait a few seconds while it guesses the port, then an alert() appears with: seed: {"id": 0.7398595146147573, "result": "pony south strike horror throw acquire able afford pen lunch monster runway", "jsonrpc": "2.0"}

(Note: i dont use bitcoin, you can steal my empty wallet if you like)

All 75 comments

Even if a hacker got access to your wallet somehow it's still encrypted with strong password i hope.

The JSONRPC interface is not about your personal wallet at home. It is mostly used by web servers for remotely executing commands, like handling a wallet via a web interface or accepting web payments.

While the electrum daemon is running, someone on a different virtual host of the web server could easily access your wallet via the local RPC port.

Currently, there is no security/authentication, giving someone access to the RPC port full access to the wallet.

Hello, I'm not a bitcoin user, a colleague pointed me at this bug report because localhost RPC servers drive me crazy 馃槢.

I installed Electrum to look, and I'm confused why this isn't being treated as a critical and urgent vulnerability? If this bug wasn't already open for months, I would have reported this as a vulnerability, but maybe I misunderstand something.

The JSON RPC server is enabled by default, it does use a random port but a website can simply scan for the right port in seconds.

I made you a demo. It's very basic, but you get the idea.

If you did set a password, some misdirection is required, but it's still game over, no?

Here is how I reproduced:

  • Install Electrum 3.0.3 on Windows.
  • Create a new wallet, all default settings. I left the wallet password blank - the default setting.
  • Visit in Chrome.
  • Wait a few seconds while it guesses the port, then an alert() appears with: seed: {"id": 0.7398595146147573, "result": "pony south strike horror throw acquire able afford pen lunch monster runway", "jsonrpc": "2.0"}

(Note: i dont use bitcoin, you can steal my empty wallet if you like)

Looks like electrum unconditionally returns a positive CORS pre-flight check. Looks like a serious issue.

The code doing this dates back to the original implementation: https://github.com/spesmilo/electrum/blob/2c67de8f642a182dd76c706b65c14eeeeee64d03/gui/jsonrpc.py#L32-L42

I suspect this should just be removed, but there may be a reason it's there?

thanks for pointing this out. this was introduced when the jsonrpc interface was merged with the daemon 4682d95a76459a5fe837630f83f60653c3f32c5a

Thanks for investigating so quickly, in my opinion this merits a new release and an announcement, what do you think?

I think just scanning for people in the background of a website is really easy, and seems likely someone will try that. Even with encrypted wallets, you can still change options, change destination addresses, deanonymize users via listaddresses and so on.

Maybe there is a way to do more, like setting requests_dir to the wallet directory? I noticed if you set {method:"gui" param=[{uri: <bitcoinuri>}] it will silently change any address you've already entered - that seems kinda scary.

indeed we will do a new release

A new release (3.0.4) is available on the website and on Google Play, that disables CORS.
We may enable it again after we add password protection.

TBH simply disabling CORS doesn鈥檛 seem to be a proper solution, given that there is plenty of software other than browsers that runs locally.

I鈥檇 expect this RPC server to at least be disabled by default and, even better, password protected, given that, I suspect, the vast majority of users never use it and don鈥檛 even know that it exists.

@kirelagin The application itself uses the RPC server to work. Password protection is currently being implemented.

@SomberNight Oh, I see.

In that case you鈥檒l still need a way to securely agree on a password betwen the daemon and the GUI app. I mean, if you simply write the password to a file for the GUI to read, rouge local apps will also get it from there :(.

@kirelagin Yes, I know. Though the same apps might as well go for the wallet file directly, right?

@SomberNight Yep, you are right, there is nothing you can do about that, so that鈥檚 the problem of the user who doesn鈥檛 set a password.
Though, as @taviso pointed out, signing transactions is not the only issue, being able to modify GUI input fields via this API is also a serious one.

Is it correct that without explicitly loading the wallet with electrum daemon load_wallet one cannot run commands against the RPC? So a "normal" desktop user of electrum cannot be attacked, right?

good work guys. We ported the patch to E.C. thanks.

@h43z It is not correct. The RPC daemon is started automatically as soon as you launch the GUI app.

@h43z No, there is a load_wallet rpc, method=daemon, params=[{subcommand: 鈥渓oad_wallet鈥渳].

got ya guys. One can load the the wallet via rpc... :man_facepalming:

To sum up the parts that are probably the most interesting,
on an internet-connected device, when you open a website that exploits this, if Electrum (pre-3.0.4) is running at that time,

  • the xpub of any wallet can be read
  • the seed words/private keys can be read directly IF your wallet has no password set

    • if there is a password, the ciphertext can not be retrieved, only online bruteforce is possible (making a new json-rpc request for every password-retry)

Perhaps better than a local file with a password would be a wrapper script that:

  • generates a random key
  • starts the GUI, passing the key via stdin
  • starts the backend, passing the key via stdin
  • forgets the key (by exiting, for example).

The GUI and backend can then encrypt all RPC messages using the shared secret key.

If the threat-model includes rogue local applications running as the user, these could become a man-in-the-middle by listening on an unprivileged port (while changing the Electrum front-end config to point at this).

Just disabling CORS is still vulnerable to a DNS rebinding attack. It needs to be authenticated.

@cpacia don't browsers cache DNS lookups to prevent DNS rebinding attacks?

I do agree that authentication would be good though, but I'm curious about the level of urgency.

Should it be announced that chances are that many Electrum wallets have been hacked?
Or let's assume that getting millions (billions) from users was not something interesting for hackers ...

@pooler, please take a look at this. I think it should be as easy as pull --rebase to merge the fix to electrum-ltc

Note for users who are not familiar with GitHub: You should upgrade your client right now, even if this issue has not been closed. The 3.0.4 release includes @mithrandi's patch, which addresses the vulnerability pointed by Tavis. That vulnerability affects all users, not only daemon users.

This issue will remain open until we add password protection to the jsonrpc interface, as initially suggested by @jsmad. Password protection is needed for merchants/websites who need to use an electrum daemon from a remote machine.

For end users, upgrading to 3.0.4 is the easy part. The hard question is: Do we now need to move all our BTC to new wallets, with new seeds? It will be helpful if some guidance can be provided to help users evaluate how much risk they were exposed to in the past, based on the procedures they have usually followed. In the absence of a bijective send, moving all BTC to a new wallet can be quite labor-intensive.

@fortran77 moving coins to a new wallet might be possible to observe at https://dedi.jochen-hoenicke.de/queue/ when performed by a broader audience, i.e., there will be a huge peak in # of transactions
the hardest parts are i) to ensure that the updated version made in a rush does not contain yet another vulnerability, ii) tons of phishing attempts might appear to happen, e.g., it has been reported on reddit that some phishing electrum wallet sites appear as top-1 google ads
it might be handy to have an option to inform users via some internal warning message of their wallet application

On our webserver we have only a watch wallet, so it's not a big issue for us (just public key right)?

@SomberNight does this affect android? Does the pin number serve as protection in the same way that wallet encryption does?

what if already encrypted the previous wallet version?

Do we need to upgrade to newest version

@msadar yes you need to upgrade
@fyookball yes, it affects android. the patch protects the wallet from malicious websites, but not from malicious apps. I am about to deploy a new apk with jsonrpc disabled.

edit: new APK deployed

This is bad, but bear in mind that the RPC is only accessible to the localhost, so you're not going to have millions of people with stolen coins - their machine would already need to be compromised.
electrum

@Aranad Due to the CORS headers any website can access the RPC interface on localhost.

I don't understand how that works - upgraded to 3.0.4 now anyway :-/

@Aranad You agree that if you enter http://123.123.123.123/ into your browser, the browser will try to connect to that address?

I think you must have thought that http://127.0.0.1/ is special, but it isn't, the browser treats it the same as any other address. This means that using a standard called Cross-Origin Resource Sharing, websites can communicate with each other. Now that you know "localhost" is not treated any differently to "google.com" or "facebook.com" or "192.168.0.1", maybe you can see why this works.

You visit http://attackwebsite.com (which could also be an ad iframe on any website), that website uses CORS to connect to http://localhost, which the browser sees no differently to any other website.

@aranad WIth the CORS header set to "*" (as it is before this patch) this allows any "cross-origin" request (which is normally disallowed for JavaScript). So, e.g., some JavaScript in a Web page from evil-advertisement.example.com can make a request to 127.0.0.1:1234 or whatever.

A more legitimate use of CORS can might be so GitHub.com could allow a completely different Web site's JavaScript to make requests via their API (for example, I didn't check if they allow this). See https://en.wikipedia.org/wiki/Cross-origin_resource_sharing

@taviso and @meejah thanks for explaining :-) I get that localhost is a normal IP, just didn't know about CORS headers allowing things in any page to access it, glad I'm all updated now - I hope everyone gets updated before port scanners start finding anything!

@Aranad it's very easy to do https://twitter.com/h43z/status/950080318601560066 it could be done by any website you visit.

Just to clarify - the CORS issue is only relevant if you ever ran a web browser on the same machine as Electrum.

Also, if you installed any untrusted code (e.g. any potentially malicious app on Android), that code could have accessed your wallet on localhost via a TCP socket.

@devrandom @cpacia is correct, this is very much still exploitable via DNS rebinding which can be verified via a very simple curl (tested on 3.0.4 on macOS):

$ curl http://localhost:53887/ -X POST -d "{}" -H "Host: attackerdoma.in"
{"id": null, "jsonrpc": "2.0", "error": {"code": -32600, "message": "Request invalid -- no request data."}

While certain browsers have added a variety of mitigations for dns rebinding (including dns caches) they are trivial to bypass. For more info see the talk I gave a few months ago about the current state of dns rebinding mitigations in modern browsers: https://www.youtube.com/watch?v=Q0JG_eKLcws

As a short-term fix instead of adding authentication which may break current implementations using the JSONRPC api, I'd suggest adding a "Host" header check, similar to the one implemented by the kubernetes team: https://github.com/kubernetes/kubernetes/pull/9287/files#diff-72ebccbb2d732bfd63514a751ab57377R32 It's not perfect and authentication should be added in the long-term, however it would significantly reduce the risk of exploitation in the short-term.

Is this a problem with all wallets that open a port for RPC like geth and bitcoin core?

@Aranad I'm not sure about Geth, but based on the default Bitcoin Core installation I just tested on macOS, RPC is not enabled by default and requires authentication (specifically -rpcuser and -rpcpassword) which mitigates this issue (assuming the user sets a strong password).

Wouldn't it be a good idea to simply switch off JSON RPC by default completely - 98% of regular users won't need it and add an option to the preferences to enable it by demand ?

Just disabling CORS is not enough, you can still send commands to the RPC using a regular form and text/plain as content-type, which will not enable preflight.

For example, the following code will still allow the POST to be done, without preflight, and the command will be allowed by Electrum 3.0.4:

<form action="http://127.0.0.1:59768/" method="POST" target="x" enctype="text/plain">
    <input type="submit" value="Start" />
    <input type="hidden" name='{"id":0,"method":"gui","params":[{"url":"bitcoin:1Jsjd6xL9NPzzUY5FxM7y614FFVKeg3QbM?' value='"}]}' />
</form>
<iframe src="about:blank" name="x" id="x"></iframe>

I have made a small PoC that is also able to find the port in Safari, since it's a bit trickier to find a port that only gives status 200 using POST: https://gist.github.com/fransr/690e9ae6ce918d2e913ce6cb55ffbcae

Movie is here: https://twitter.com/fransrosen/status/950124848126316544

A quick fix would be to only allow the proper content-type for the API-calls, but I agree with @ocminer and @taviso on not having an open port at all as per default.

We really shouldn't be publishing PoCs before the devs had a chance to fix the issue. Good spot though, you're doing God's work!

I believe the issue is now fixed:

  • the JSONRPC interface is password protected
  • the JSONRPC commands are all disabled if the GUI is running, except 'ping', which is used to determine if a GUI is already running

@IonutBajescu I'm sorry for that. There were a lot of discussions going regarding updating to 3.0.4 to be safe, but I really wanted to emphasise that wasn't really the case. I would suggest some form of private channel in the future to communicate security issues, so people do not rely on telling them to you publicly on GitHub, and also mention that in the readme.

@fransr no problem. you can use IRC for private interactions. Thanks for your work.

@ecdsa, first of all, thank you for the updates.

I would like to mention that I initially explained this issue in the IRC channel, but I was not taken seriously. Probably because I was talking about the daemon on its own and not the GUI.

Another feature I'd like to see, is sockets, in addition to password protection. Many Linux daemons use ports but they also use unix sockets as an alternative, sockets can have proper ownership permissions, thus limit access on a shared hosting environment (watch-only wallets is a typical use).

Thank you.

my question: is it safe to type password (passphrase) with bare keyboard or use windows virtual keyboard

@anacondabitch if you believe there is a keylogger on your computer, using the virtual keyboard should help.

@allanhorwitz no its an attack

Is there a CVE id for this? Distros typically don't know packages need to be updated without one.

Even with the fix in place, any wallets that were already compromised (but possibly not taken advantage of yet) are still compromised and should be replaced, correct?

@zatricky I just submitted one

@nwsm correct.

If you have any reason to suspect your wallet has been compromised, you shall create a new one (with different seeds), put a passphrase on it and transfer your coins from old compromised wallet to new one.

there must some sort of internal communication system so that every user will get announcements about critical vulnerabilities like the one described in this thread
otherwise, it is very irresponsible to believe that the users under risk (the ones who didn't encrypt their wallets) are familiar with github && check reddit/twitter news during NY vacations.

@loshchil it is irresponsible itself if a user decides not to encrypt their wallets.
Also, users don't need to be familiar with github or anything else. They just need to keep their software up-to-date.

However, I agree that we need a proper way to let users know there are critical bugs.
Are you able to come up with a solution and propose it in a PR?

@mautematico

They just need to keep their software up-to-date.

The current situation we are in is a good example that the above-mentioned view is hard to defend if user's security is taken into account. More specifically, a few moments after the vulnerability appeared on github, a ton of responsible users who used the most recent version so far have become targets to trivial exploits (i.e., hundreds or thousands of hackers are qualified to implement them) which could allow to hack wallets with or without brute-forcing their passwords.

I appreciate your proposal to come with a solution and a PR. However, I will limit my contribution to this reply here.

My proposal would be to
i) Make Electrum regularly check whether a more recent version is available.
ii) Modify Electrum main window title/caption "Electrum x.y.z" to "Electrum x.y.z TEXT",
where TEXT depends on the situation we are in. For instance, it can be empty, "(is not safe to use)",
"(outdated but does not have known vulnerabilities)", "(outdated and has known vulnerabilities)"
iii) Update Electrum.org to have a section where known vulnerabilities are described version-wise and a set of best practices to deal with them is presented.

@attritionorg, invalid reference, because that bug i submitted is not by any means related to this issue, if you had properly read and understood the bug report you would understand that, but youre probably too busy sending people boxes of feces to care

@ecdsa

what if I never access to the previous version and deleted the wallet software? which means keeping as cold storage?

@msadar you were only susceptible to an attack while Electrum was running and your wallet unlocked.
Nevertheless, as it is unknown whether the bug has been exploited, it might be worth to create a new cold wallet / Electrum wallet, encrypt it, and transfer your funds to it.

It is an excellent example why you should use only the ported version:
because the ported version (even with bug(s)) in most cases is used for a very short time (set cd/usb stick, do stuff, then remove it), while installed version is very probably to works all time!

@ecdsa re CVE id, is there a place where we will know it has been issued? Or will you be posting it here when it has been issued?

That sheet is for assignments requested via DWF, a CNA that handles some open source software. If you request via the form on MITRE's web site, you won't be able to look it up until it is published, or the requesting party receives the assignment and posts it here.

Hi. Do you need help getting a CVE assigned, or is the process already in progress? I could ask the Debian security team for one, if it is useful.

@petterreinholdtsen I filled the form on MITRE, and my request is listed on the document linked above. Is there something else I need to do? I am not familiar with the process.

I'm not sure either, but have no better suggestion. I asked on #debian-security and it seem to be the recommended approach based on the feedback there.

The assigned CVE for this issue looks to be CVE-2018-1000022

@carnil have a reference for that? CVE-2018-6353 was assigned and opened:

http://cve.mitre.org/cgi-bin/cvename.cgi?name=2018-6353

CVE-2018-6353 is for #3678, a different issue.

@attritionorg: it was apparently assigned by DWF project. I got that confirmation by MITRE, since I stumpled over the CVE when I was investigating CVE-2018-6353, which mentioned "a different vulnerability than CVE-2018-1000022". I queried about this MITRE, who confirmed that DWF has assigned the CVE (but not yet published back?).

As @mithrandi stated the CVE-2018-6353 is for #3678, whereas CVE-2018-1000022 is for #3374

Someone could please delete file posted by @Ruethairat?

Was this page helpful?
0 / 5 - 0 ratings