Lucene search

K
hackeroneBnoordhuisH1:1690000
HistorySep 02, 2022 - 7:03 p.m.

Node.js: Weak randomness in WebCrypto keygen

2022-09-0219:03:49
bnoordhuis
hackerone.com
64

9.1 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

NONE

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N

6.4 Medium

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

NONE

AV:N/AC:L/Au:N/C:P/I:P/A:N

0.001 Low

EPSS

Percentile

22.8%

https://github.com/nodejs/node/pull/35093 introduced a call to EntropySource() in SecretKeyGenTraits::DoKeyGen() in src/crypto/crypto_keygen.cc. There are two problems with this:

  1. It does not check the return value, it assumes EntropySource() always succeeds, but it can (and sometimes will) fail.

  2. The random data returned byEntropySource() may not be cryptographically strong and therefore not suitable as keying material.

An example is a freshly booted system or a system without /dev/random or getrandom(2).

Impact

EntropySource() calls out to openssl’s RAND_poll() and RAND_bytes() in a best-effort attempt to obtain random data.

OpenSSL has a built-in CSPRNG but that can fail to initialize, in which case it’s possible either:

  1. No random data gets written to the output buffer, i.e., the output is unmodified, or

  2. Weak random data is written. It’s theoretically possible for the output to be fully predictable because the CSPRNG starts from a predictable state.

The output buffer is allocated in SecretKeyGenTraits::DoKeyGen() using OPENSSL_malloc() (alias for CRYPTO_malloc()), which in turn calls malloc().

malloc() does not zero the buffer but its contents may be predicted or manipulated by an external attacker, e.g. by manipulating an arraybuffer, then forcing the GC to reclaim it.

Users can override the CSPRNG (and do) so there are probably more failure modes. A buggy CSPRNG could write out only zeroes, for example, comparable to (2).

I have a (trivial!) patch available. H1 gives this a really high CVSS score but I suppose that’s appropriate when the worst case failure mode is a complete breakdown of confidentiality and integrity.

9.1 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

NONE

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N

6.4 Medium

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

NONE

AV:N/AC:L/Au:N/C:P/I:P/A:N

0.001 Low

EPSS

Percentile

22.8%