ssh icon indicating copy to clipboard operation
ssh copied to clipboard

Patching PublicKeyCallback for CVE-2024-45337

Open alecb-stripe opened this issue 1 year ago • 6 comments

From [security] Vulnerability in golang.org/x/crypto:

For example, an attacker may send public keys A and B, and then authenticate with A. PublicKeyCallback would be called only twice, first with A and then with B. A vulnerable application may then make authorization decisions based on key B for which the attacker does not actually control the private key.

golang.org/x/[email protected] enforces the property that, when successfully authenticating via public key, the last key passed to ServerConfig.PublicKeyCallback will be the key used to authenticate the connection.

I'm worried that this fix isn't sufficient given this package's use of PublicKeyCallback, because applyConnMetadata only ever sets context values on its first call:

https://github.com/gliderlabs/ssh/blob/adec695b0aa80b0a03f251e1f8c302f0ea192ef5/context.go#L114-L116

I.e., the fact that v0.31.0 makes additional calls to PublicKeyCallback won't actually help here, because only the values from the first call get stored in the ctx.

Does that seem correct? If so, should applyConnMetadata be patched so that we used the values from the last call? Or would some other patch be appropriate?

alecb-stripe avatar Dec 11 '24 20:12 alecb-stripe

I'm still looking at this - I hope to have a closer look tonight.

I think you're right, that we should store the public key from the last call to PublicKeyCallback, but I want to make sure before pushing out a pre-mature fix.

EDIT: this is not correct, see below.

belak avatar Dec 12 '24 00:12 belak

I don't know if applyConnMetadata is the problem here. None of the value it sets will be change between calls to PublicKeyCallback with different keys AFAIK?

However, storing the public key value in the connection context inside PublicKeyCallback surely is problematic because the last call to this callback will set the final value of the public key in the context, which is not necessarily the key used to authenticate? i.e. this seem vulnerable: https://github.com/gliderlabs/ssh/blob/adec695b0aa80b0a03f251e1f8c302f0ea192ef5/server.go#L163

But I guess with the updated behaviour in 0.31.0 it will no longer be a problem.

smlx avatar Dec 12 '24 01:12 smlx

Yeah, it's been a while since I've looked at this code, but I believe updating to 0.31.0 will be sufficient. It seems like the alternative is to store the public key in the Permissions.Extensions, but that would require marshaling and unmarshaling the public key because it's a map[string]string rather than a map[string]any.

The simplest solution is to update x/crypto to 0.31.0, which I will do later tonight.

belak avatar Dec 12 '24 04:12 belak

I've pushed commit a8ecd3ed244fb77c863c0cf30ccdcca44436974a, but I don't have a great way to verify the change. Because this is a standard dependency bump, I don't have a problem tagging a new version, but I'd like to have a way to verify the behavior is correct before closing this.

belak avatar Dec 12 '24 05:12 belak

I've tagged the previously mentioned commit as v0.3.8, to allow people to easily update to a version of x/crypto which should resolve the issue.

However, we're still leaking Permissions data between auth callbacks, which could result in a similar issue to the x/crypto CVE if used incorrectly.

Because of this I've opened https://github.com/gliderlabs/ssh/pull/243 which aims to make Permissions harder to misuse, and avoids attaching public keys users don't actually have the corresponding PrivateKey for to the Context.

belak avatar Dec 12 '24 08:12 belak

We're now using a fork and made the connection permission public. So we can use the key from auth handler

https://code.forgejo.org/forgejo/ssh/commit/5fc306ca0616d1b05ce8f81c480ea6ee21ebb2c0

viceice avatar Dec 12 '24 09:12 viceice