Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

node-rsa vulnerable to the Marvin Attack #230

Open
tomato42 opened this issue Nov 25, 2023 · 18 comments
Open

node-rsa vulnerable to the Marvin Attack #230

tomato42 opened this issue Nov 25, 2023 · 18 comments

Comments

@tomato42
Copy link

(since I have haven't found a security policy or an email to report security vulnerabilities I'm filing it directly here)

I've verified that the node-rsa 1.1.1 package running on node 21.1.0 is vulnerable to the Marvin Attack (a timing variant of the well-known Bleichenbacher attack).

I've executed the script on Ryzen 5 5600X on an isolated cpu core.

The summary of the test:

Sign test mean p-value: 0.3691, median p-value: 0.2482, min p-value: 0.0
Friedman test (chisquare approximation) for all samples
p-value: 0.0
Worst pair: 3(no_structure), 5(valid_0)
Mean of differences: -3.17599e-05s, 95% CI: -3.24520e-05s, -3.114535e-05s (±6.533e-07s)
Median of differences: -3.20305e-05s, 95% CI: -3.22410e-05s, -3.179000e-05s (±2.255e-07s)
Trimmed mean (5%) of differences: -3.17426e-05s, 95% CI: -3.19244e-05s, -3.155255e-05s (±1.859e-07s)
Trimmed mean (25%) of differences: -3.18371e-05s, 95% CI: -3.20280e-05s, -3.163763e-05s (±1.952e-07s)
Trimmed mean (45%) of differences: -3.19491e-05s, 95% CI: -3.21577e-05s, -3.173588e-05s (±2.109e-07s)
Trimean of differences: -3.18982e-05s, 95% CI: -3.20940e-05s, -3.168987e-05s (±2.021e-07s)
Layperson explanation: Definite side-channel detected, implementation is VULNERABLE

conf_interval_plot_trim_mean_05
the description of the probes:

ID,Name
0,header_only
1,no_header_with_payload_48
2,no_padding_48
3,no_structure
4,signature_padding_8
5,valid_0
6,valid_48
7,valid_192
8,valid_246
9,valid_repeated_byte_payload_246_1
10,valid_repeated_byte_payload_246_255
11,zero_byte_in_padding_48_4

explanation of the probes is in the step2.py script.

Given the large size of the timing signal, the attack will be easy to perform remotely.

@rzcoder
Copy link
Owner

rzcoder commented Nov 25, 2023

Did I understand correctly that the vulnerability essentially necessitated access to the machine running node-rsa code?

@tomato42
Copy link
Author

Did I understand correctly that the vulnerability essentially necessitated access to the machine running node-rsa code?

No, absolutely no. It's measurable over the network, see the linked papers from the vulnerability page.

I haven't made an experiment with a side-channel this huge, but I'd say even attacking a server good few hundred kilometers away, with a RTT of few milliseconds should be entirely doable with reasonable attack time. Attack from within the same data centre will be a manner of few hours per decryption.

@rzcoder
Copy link
Owner

rzcoder commented Nov 25, 2023

Is it same result with default pkcs1_oaep scheme?

Also, can you pls confirm same result with keyObj.setOptions({environment: "browser"})? Probably yes, just wondering.

@tomato42
Copy link
Author

with keyObj.setOptions({environment: "browser"}) set (jut added it after keyObj.setOptions({ encryptionScheme: {scheme: algName}});) it's even worse:

conf_interval_plot_trim_mean_25

  1. because the side-channel is much larger (100µs vs 32µs)
  2. it looks like the length of the padding is not checked: the valid_246 has a PS of 7 bytes, when the standard specifies a minimum of 8

I don't see anything similar when running OAEP (without "browser" set), but then I haven't ran a large sample size, so it may still show up. But the speed of decryption would suggest that in nodejs environment it's just delegating to node? If that's the case, then there's no need to check OAEP: learning about error there doesn't provide information to the attacker

@tomato42
Copy link
Author

@rzcoder any progress on this?

@rzcoder
Copy link
Owner

rzcoder commented Feb 2, 2024

@tomato42 It doesn't seem like anything can be fixed here. The engine on pure JS is used only in client-side code, and shouldn't be vulnerable to such an exploit through many requests. And the nodejs methods relate to nodejs/OpenSSL projects.

@tomato42
Copy link
Author

tomato42 commented Feb 2, 2024

It doesn't seem like anything can be fixed here.

Dropping support for PKCS#1v1.5 encryption would fix the issue... That's what jsrsasign did for CVE-2024-21484

and shouldn't be vulnerable to such an exploit through many requests

How so?

@tomato42
Copy link
Author

tomato42 commented Feb 2, 2024

It doesn't seem like anything can be fixed here

as I said, "it looks like the length of the padding is not checked:", that's an outright bug in the implementation...

@rzcoder
Copy link
Owner

rzcoder commented Feb 2, 2024

How so?

Not a real world use case.

it looks like the length of the padding is not checked

Ok, if just this. Can you please check version from https://github.com/rzcoder/node-rsa/tree/check_pkcs1v1.5_padding_size ? Is it gets any better?

@tomato42
Copy link
Author

tomato42 commented Feb 2, 2024

Not a real world use case.

Sorry, this is a security sensitive API. The package has nearly a thousand dependencies and over half a million weekly downloads. I doubt that it's "not a real use case" for each and every user of this library.

https://github.com/rzcoder/node-rsa/tree/check_pkcs1v1.5_padding_size

sorry, don't have the time to run tests. Having the unittests verifying correct behaviour would make it much easier to review...

@rzcoder
Copy link
Owner

rzcoder commented Feb 2, 2024

I doubt that it's "not a real use case"

This particular behaviour is present only in the client-side browser, which is usually does not handle incoming requests that can exploit this vulnerability, especially with a specific scheme that is not set by default. Therefore, I am quite sure that there is no real-world use case for this in the wild. Otherwise, this vulnerability will not be the biggest problem, I think...

@tomato42
Copy link
Author

tomato42 commented Feb 2, 2024

I still don't see it: just because the code is running in the browser doesn't mean that the server is trusted. It can be providing malformed messages specifically to decrypt data it has no access to. I mean: why else would anybody run RSA decryption using javascript in the browser otherwise?

@rzcoder
Copy link
Owner

rzcoder commented Feb 3, 2024

I agree that this is a possible situation. But in any case, the client needs to start interacting with the malicious server himself; this is not a situation where an attacker can connect on his own initiative.

Any way, if you'll have time, please run tests on https://github.com/rzcoder/node-rsa/tree/check_pkcs1v1.5_padding_size if it any better I'll merge it to master.

@tomato42
Copy link
Author

tomato42 commented Feb 5, 2024

There are situations where the server doesn't have to be malicious, just a participant: like capturing keys through sound or leaks that happen through power LEDs.

Sorry, I won't have the time to test this code any time soon.

@jlkalberer
Copy link

Any update on this?
I'm hoping that I don't have to start using the --security-revert=CVE-2023-46809 when I start my project :)

I looked at the script to run the timing attack but I don't even know where to start with that.

@tomato42
Copy link
Author

tomato42 commented Apr 3, 2024

What do you mean you "don't know where to start"? There are step-by-step instructions linked in the first first post of this issue: https://github.com/tomato42/marvin-toolkit/tree/master/example/node-rsa

Also, you need to use --security-revert=CVE-2023-46809 only if you use OpenSSL without implicit rejection. Fedora, RHEL, and Ubuntu (there may be others, I'm not tracking that) have backported implicit rejection from 3.2.0 to earlier versions.

@jlkalberer
Copy link

@tomato42 - yes, I looked at those instructions and it's pretty clear that I'd have to spend half a day or longer getting that environment set up.
Would it be possible to set all this up in a docker container? (Would that even work for the attack?)
I'm sure that would get you a better response from the maintainers as it would be much easier to follow your instructions on a container that already has all the dependencies pulled down.


I'm not a security expert so please excuse my ignorance on this but what you're saying about the --security-revert=CVE-2023-46809 is that various distros are patching the bug. That means that even if this package isn't fixed, it is covered by the distros?

@tomato42
Copy link
Author

tomato42 commented Apr 3, 2024

Would it be possible to set all this up in a docker container? (Would that even work for the attack?)

is it possible? yes, and to confirm such large side-channels as those one here, it will work fine. Do I recommend it for verification that the issue was fixed? no. The closer to the hardware the test can be executed, the less noise there should be and thus the less data needs to be collected. Containers may be thin enough to not matter, but I haven't verified it.

I'm sure that would get you a better response from the maintainers as it would be much easier to follow your instructions on a container that already has all the dependencies pulled down.

the instructions and scripts don't require installation of any software outside of python virtual environments. As long as you have git, openssl, bash, and Python 3.7 or later, you have everything you need to run the tests... Introducing containers would make it more complex, not less. If you feel more confident in running them in containers, just grab any recent Linux distro and run the scripts in the container.

I'm not a security expert so please excuse my ignorance on this but what you're saying about the --security-revert=CVE-2023-46809 is that various distros are patching the bug. That means that even if this package isn't fixed, it is covered by the distros?

not exactly sure what you're asking...

if it is: "Is it possible to workaround the issue by changing just OpenSSL, without Node.js?", then the answer is Yes. The change in Node.js is just to make sure that an insecure API is not available. If it can be safely used, then the API is re-enabled. If not, then you have to use the command line switch to re-enable it, thus making your application potentially vulnerable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants