I’ve discovered that this attack against automatically-generated distributed Erlang cookie file (aka ~/.erlang.cookie ) is presumably effective at least since OTP 18.0 (in 2015), and the security hole isn’t fixed as of OTP 28.3.1.
While choosing something more secure, such as using TLS between distributed Erlang nodes, is strongly preferred, remaining this sort of vulnerability as default is not good.
An obviously possible workaround is to use cryptographically strong PRNG to generate the cookie file content, which requires crypto module. The PRNG in auth.erl is indeed weak to be thoroughly exploited in a short time. Also, the seeding function depends on boot timing, which would not have much diverse output (i.e., of small entropy) between multiple booting attempts of BEAM.
Another radical approach would be banning the automatic generation of weak cookies altogether.
I am wondering what should be done to this known security hole.
I think the problem is that the connection made is no longer accidental but deliberately exploited.
The cookie mechanism is only supposed to prevent from your own accidental connections to nodes you don’t intend to. In that case you don’t have to crack the cookie, you already know it (since you set it in your own infra setup).
The seed is highly predictable due to the usage of erlang:monotonic_time(), which starts from zero at the boot time of BEAM, and erlang:unique_integer(). The result of seed value is predictable as described in erl-matter README.md. In my case on macOS 26.2 running on Mac mini 2023, the value was within (3.8 to 4.2) * 10^8.
Guessing the seed from the generated string is easy due to the simple linear congruential generation method of the cookie string.
Unencrypted distribution should only be used in a trusted network, think backplane network connecting blades in a server rack. Documentation clearly states that. In an untrusted network, man in the middle doesn’t even need to know the cookie to perform attacks, I believe.
Of course once a cookie is stolen you can do anything. And I 100% agree with what’s written in the documentation. OTOH, I think using a weak PRNG is something which should be fixed, because Erlang/OTP already has a far better PRNG implementation.
@jj1bdx: Your PR would have made it harder to guess the cookie, and harder to reverse calculate the seed from a known cookie since using erlang:system_time() instead of erlang:monotonic_time() probably increases the entropy a bit, and because the PRNG is no longer an unscrambled LCG.
I think that just using the default automatic seed in rand would have been slightly better since it maybe adds another few bits of entropy (the node name and a hash of the process generating the seed), but more importantly it does not just XOR all the entropy bits onto each other, instead it feeds them into iterations of SplitMix64, which should to preserve the entropy better, and make it harder to reverse calculate the seed).
Nevertheless, with such an improvement, it would have been harder to write a toolbox to “crack” the Erlang auto generated cookie, so it may not have been written.
Now some projects that have kept the Erlang distribution port exposed gets a proper slap on their fingers for not reading the documentation warnings … which is a good thing.
Thank you @jj1bdx for bringing back this matter to the community’s attention!
It may be that the entropy of erlang:system_time() is also not very large, since the point in time when the automatic cookie was generated may be predictable. If you know the time within a week the estimated entropy would be at most 49 bits. As an edge example, we have heard of products that cold boot and generate the cookie before the correct time has been acquired, so the clock was just after 1 Jan 1970 where the clock chip starts off. In such systems it can be really problematic to find decent entropy.
Thank you for the pointer to Sagemath! I know that the author of our rand algorithms, and the author of the competing Permuted Congruential Generators have been in a word feud / verbal pie throwing regarding the predictability of PRNGs, and then reverse calculated each other’s generators and scramblers. So any PRNG that is not cryptographically secure can be reverse calculated, with more or less effort. Their debate was related to the one in this thread - is a middle class of security (hard to predict) between cryptographically secure and completely predictable useful, or would such a class of security just give a false sense of security so it should be avoided…
Thanks for the mention of the the “pie throwing” between the PRNG designers, it was new to me.
There’s a calm description and demonstration on John D. Cook’s blog, with the throwers making an appearance in the comments; I thought it was interesting enough to read:
That was a quite civil tone, but it is that very dispute. Melissa O’Neill says Sebastiano Vigna’s generators are “trivially predictable” and strives for something better (according to some definition). Vigna says - that’s pointless and yours, just like any other PRNG, are also predictable.
Well, there is no solution that Erlang/OTP can implement, except to advise projects to not expose the unsecure distribution port.
We could change some defaults, so using the distribution gets harder, but the question is if there is a good enough compromise between ease of development vs. smaller footgun…
In addition I would also like to point out that the Erlang cookie is explicitly mentioned in a Security section. This section also mentions things like “random strings”, “built into the system at the lowest level” etc.
This doesn’t sound like a big red warning that the cookies are insecure and should never be used to secure (public) nodes. On the contrary, it does write that the cookie implements security…