Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.
Sign upSLIME is insecure and easily allows local attackers to execute arbitrary code #286
Comments
This comment has been minimized.
This comment has been minimized.
I suppose the vast majority of SLIME users are on single-user machines. Definitely something we should do at some point, though. #270 is a first stab at implementing your AF_UNIX suggestion, but it might be a better idea to use the same solution on Windows and UNIX for better maintainability. |
This comment has been minimized.
This comment has been minimized.
I have come up with a plan of attack. Part 1 is to enable use of Unix domain sockets. Much of this code can be taken from the Emacs server code within Emacs itself. This fixes the problems forever on must Unix systems, unless ABCL or LispWorks is used. ABCL, being a JVM language, does not support Unix domain sockets without a JNI library. I couldn't figure out how to change the LispWorks code since it uses undocumented functions and I don't have LispWorks. Part 2 is securing transport over TCP sockets. My plan here is, essentially, to make the existing |
This comment has been minimized.
This comment has been minimized.
Just to have clear understanding of the security/convenience tradeoff, does proposed solution support these scenarios arouns
If the things above do not work or do not have a good alternative, please consider leaving "old" way as a (possibly opt-in) option. The Disclaimer: I am not a slime maintainer, just a (possibly affected) happy user. So do not feel bound by my opinions. |
This comment has been minimized.
This comment has been minimized.
Note that this vulnerability is probably more severe than obvious: we just published a fix for this in Guile. https://lists.gnu.org/archive/html/guile-user/2016-10/msg00007.html Basically, using DNS rebinding attacks, you can even attack a "localhost-only" connection via users' web browsers. So yes, it should currently be possible to have users visit web pages that allow attackers to execute any lisp code on a user's machine. I'd highly recommend adding support for unix domain sockets ASAP. |
This comment has been minimized.
This comment has been minimized.
I think that there are a few uses for that though. I develop on remote Android ECL process from my Emacs on Linux box. Another scenario is debugging remote client application (never tried this one though - this should be secured obviously). Remote connections shouldn't be wiped out entirely (but I think that making it opt-in would be reasonable). |
This comment has been minimized.
This comment has been minimized.
to clarify the attack: if you have a swank listening on from the linked email:
|
This comment has been minimized.
This comment has been minimized.
@attila-lendvai Yes that's exactly right. I see that there's a pull request at #291 to add support for unix domain sockets. Glad to hear it... I think that's the right solution. |
This comment has been minimized.
This comment has been minimized.
I think that the ultimate solution is cryptographic authentication of all The solution is threefold:
On Oct 11, 2016 5:41 PM, "Attila Lendvai" notifications@github.com wrote:
|
This comment has been minimized.
This comment has been minimized.
Personally, if a Windows solution is not yet ready, I think that the right option is to make the :unix option the default with unix domain sockets and leave the old tcp code in place, signaling a warning. (You could likewise try to add a guard that closes HTTP connections when discovered, the way the Guile code has.) This way users have a secure option by default. Currently users are known to just be left vulnerable. If there's a solution now, let's use it. If an authentication system, which needs to be figured out, becomes available in the future, great. But maybe let's worry about that then? |
This comment has been minimized.
This comment has been minimized.
Hi! It's been a while and I haven't seen any movement on this. Meanwhile, users are still vulnerable. I've considered using common lisp for some projects but have stayed away from it because of this issue for now. I still think doing the quick solution of using unix domain sockets is best for now; at least provide it as an option? I'd love to help but I'm not familiar with SLIME's code at all, and am already swamped with other tasks. Sorry for the mostly-ping message... I just don't think this one should be dropped on the floor! |
This comment has been minimized.
This comment has been minimized.
For local slime sessions, I don't see an issue. When slime launches a process it connects to a random port almost immediately, and no new connections are accepted. So it's all theoretical. Now, for remote sessions using an ssh tunnel the window when it's still listening is larger, but domain sockets won't help there. |
This comment has been minimized.
This comment has been minimized.
And if you want to reduce the local issue from theoretical to impossible, create ~/.slime-secret with a password in it. |
This comment has been minimized.
This comment has been minimized.
and .slime-secret can be used with remote connections as well. |
This comment has been minimized.
This comment has been minimized.
Can we make generating ~/.slime-secret from /dev/urandom the default behavior if it doesn't exist? That would make it reasonably secure by default. |
This comment has been minimized.
This comment has been minimized.
That would work for local connections initiated by slime, but not for remote connections. |
This comment has been minimized.
This comment has been minimized.
But for remote connections, it will fail, hopefully with a message at least as helpful as: "mismatch in slime secret" and the user can either duplicate the secret between machines, or disable the use of it? As an example of other projects that have made the switch, X11 switched to requiring a secret by default at some point (since I recall when it was still using xhost based authentication) |
This comment has been minimized.
This comment has been minimized.
... unless there is some other bug there (such as was #302). I am not sure that the code was written with security in really adverse conditions in mind. |
This comment has been minimized.
This comment has been minimized.
Bugs should be fixed, nobody will argue with that. |
This comment has been minimized.
This comment has been minimized.
Using .slime-secret does not make an attack "impossible," it just makes it a bit more difficult. It only means that the attacker is forced to do a man-in-the-middle attack. Other than making unix domain sockets the default, the only real fix would be to use a protocol between the Lisp process and Emacs that authenticates every message cryptographically. It would have to authenticate that every message is received, that messages are received in the correct order, etc. In other words, it would probably be easier and more secure to just start using TLS than to try to design and implement something Slime-specific. So can we please switch to unix sockets as the default, and at least reduce the scope of this bug to Windows (which I am sure has something similar, but I am not a Windows user or developer)? |
This comment has been minimized.
This comment has been minimized.
fwiw unless you accept connections from the outside world (slime accepts connections only from 127.0.0.1 by default) it would be rather hard to pull MITM attack. |
This comment has been minimized.
This comment has been minimized.
I do not think it is so hard: A local attacker could connect to the swank process first, then immediately start listening on the same port until emacs connects. |
This comment has been minimized.
This comment has been minimized.
And domain sockets prevent local connections?
And what about connections to remote servers? We can switch to whatever you propose, ssl, domain sockets, but you'll have to provide the code. |
This comment has been minimized.
This comment has been minimized.
Unix domain sockets can be restricted to a particular user; the problem with TCP is that the attacker can be a different user. Unix sockets would also be more difficult for a web browser to connect to. I am happy to help, but there seems to already be a pull request for unix domain sockets, so I am not sure what more I can do. |
This comment has been minimized.
This comment has been minimized.
You have other users on your machine attacking you? |
This comment has been minimized.
This comment has been minimized.
Indeed there is #291 that's a lot of changes, beyond my attention span. |
This comment has been minimized.
This comment has been minimized.
I do not think other users on my machine are attacking me, but that does not mean that I should e.g. give all users on the machine read access to my SSH private keys. Also keep in mind that a user is not necessarily a person; users can also be accounts created for system services, some of which may be network facing and which are run as separate users to mitigate the risk of compromise (and there has been no shortage of bugs over the years). Let's not be dismissive of security concerns, especially when the solution is not terribly difficult. If the pull request is too large, I can pitch in and help with reviewing it, or I can help to break it down into more manageable changes. Just let me know what you need (feel free to email me if you would prefer not to add more comments to this bug). |
This comment has been minimized.
This comment has been minimized.
I don't think I'll be handling this at all, unless it were a simple change changing a couple of functions. But something like that pull request goes beyond the amount of time I'm willing to allot to working on slime. I'm not against it, just no interest. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
You are free to do anything, I just don't find this issue important. |
This comment has been minimized.
This comment has been minimized.
To be sure I understood correctly: the above comment #286 (comment) explains that when starting a Swank server on a local Lisp process, the user is vulnerable to attacks when using a web browser on the side. Is this correct? If so, it seems to be critical. |
This comment has been minimized.
This comment has been minimized.
It's overblown and theoretical, not critical. And won't be solved with unix domain sockets. |
This comment has been minimized.
This comment has been minimized.
Why theoretical? It's quite easy for a website to send to localhost if I'm not mistaken. |
This comment has been minimized.
This comment has been minimized.
I replaced this with #511 so that there are no alarmist comments talking over each other with the actual information spread out over the place. |
This comment has been minimized.
This comment has been minimized.
Perhaps an interesting first step would be to try using TLS by including some of the appropriate parameters to https://www.gnu.org/software/emacs/manual/html_node/elisp/Network.html In this case, two possible improvements would be made, assuming a reverse proxy providing SSL termination to the swank server running on the remote Lisp.
Since the reverse proxy would provide SSL termination, I think this first step would require no changes to the swank server, just add support for passing parameters to the open-network-stream command. I will try this out and submit a pull request, I think. |
This comment has been minimized.
This comment has been minimized.
I realize now that this doesn't address the problem raised here of not using Unix sockets and attackers sharing the same machine. All it really does is provide another form of authentication. In any case, I've linked it here |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
The attack isn't theoretical; the Guile post I linked to talks about the actual details. We demonstrated a real attack there and had to fix it. Unix domain sockets aren't available to browsers. If they ever became so, it is true that this would no longer fix that problem. Since they aren't, I'm unsure why you think that's not a viable fix. |
This comment has been minimized.
This comment has been minimized.
@cwebber The guile post references a paper about an html form protocol attack. But according to my research and also #511
I checked that the following way: (load "$HOME/.roswell/lisp/slime/2019.05.21/swank-loader.lisp")
(swank-loader:init)
(swank:create-server :port 4005 :style :spawn :dont-close t) client: nc localhost 4005
GET / HTTP/1.1 and this closes the connection with the error that this can't be parsed as an integer. So I think slime should not be vulnerable. But I still agree that using unix domain sockets where possible is a good idea. |
This comment has been minimized.
This comment has been minimized.
Greatly appreciate the followup, @mohe2015! I assumed wank used a line-oriented protocol like Guile's did and admittedly did not particularly test. So it seems SLIME is probably not as at risk as I thought it was for HTTP, anyway. (There may be other protocols that also have clients with confused deputy problems, I don't know.) I think it still would be important to add but I'll admit that this decreases the urgency. |
SLIME is extremely insecure and allows local attackers to easily execute arbitrary code by connecting to the Swank server process.
Fortunately, the fix is simple, at least on Unix: use a Unix domain socket (
AF_UNIX
) instead of a TCP socket onlocalhost
. On Windows, use a simple, once-only secret key obtained fromRtlGenRandom()
(the basis of the better-known, and harder to use,CryptGenRandom()
) to authenticate Emacs to the Common Lisp program.The secret should be passed via a secure temporary file. Specifically, Emacs should set the file contents to the authentication key, and the Common Lisp implementation should overwrite the file with its port number. One MUST use a means of comparison that resists timing attacks (attackers can hammer
localhost
very quickly).One could also use the Windows solution on Unix, with
/dev/urandom
as the random number source.