Skip to content

Commit bd2e85e

Browse files
committed
fix: Prevent premature authentication on failed ssh key challege
Many thanks to András Veres-Szentkirályi for the report and the support in understanding and finding the issue.
1 parent ad6c6b2 commit bd2e85e

File tree

4 files changed

+72
-9
lines changed

4 files changed

+72
-9
lines changed

releases.moxie

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ r34: {
66
id: ${project.version}
77
date: ${project.buildDate}
88
note: ''
9+
This release fixes a vulnerability allowing an attacker to circumvent authentication on the SSH transport. Users are urged to update to this version.
10+
911
Should you have disabled the Flash-based copy-to-clipboard function because it wasn't working anymore (`web.allowFlashCopyToClipboard = false`), you may want to rethink this and enable it again. The configuration property has the same name, but the mechanism was exchanged. Flash is gone, and a modern JavaScript solution is now used to copy text directly to the clipboard (via clipboard.js).
1012

1113
The setting `server.requireClientCertificates` now has three values: `required`, `optional` and `none`. While `required` is synonymous to the old `true` value, and `optional` is synonymous to the old `false` value, the new `none` value results in the server never asking the client to present any client certificate at all. The old values `true` and `false` can still be used and keep their meaning.
@@ -18,6 +20,7 @@ r34: {
1820
Highlights:
1921

2022
* Support for ECDSA and Ed25519 SSH keys
23+
* Fix vulnerability that allowed SSH authentication to be circumvented
2124
* Explicitly disable requesting optional client TLS certificates
2225
* Copy-to-clipboard button is back and working
2326
* Minimal required Java version is Java 8
@@ -30,6 +33,7 @@ r34: {
3033
''
3134
security:
3235
- Fix path traversal vulnerability which allowed access to "/resources//../WEB-INF/". (CVE-2022-31268) This was fixed by updating Jetty. (issue-1409)
36+
- Fix exploit circumventing SSH authentication. Many thanks to András Veres-Szentkirályi (silentsignal.eu) for the report. (CVE-2024-28080)
3337
fixes:
3438
- Fix crash in Gitblit Authority when users were deleted from Gitblit but still had entries (certificates) in the Authority. (issue-1359, pr-1435)
3539
- Fix tab-to-space conversion to work like tabs. (pr-1065 by @QuentinC)
@@ -92,6 +96,7 @@ r34: {
9296
- Tino Desjardins
9397
- @xxl-cc
9498
- Egor Shchegolkov
99+
- András Veres-Szentkirályi
95100
}
96101

97102
#

src/main/java/com/gitblit/transport/ssh/SshKrbAuthenticator.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,7 @@ public SshKrbAuthenticator(IStoredSettings settings, IAuthenticationManager auth
5454
public boolean validateIdentity(ServerSession session, String identity) {
5555
log.info("identify with kerberos {}", identity);
5656
SshDaemonClient client = session.getAttribute(SshDaemonClient.KEY);
57-
if (client.getUser() != null) {
58-
log.info("{} has already authenticated!", identity);
59-
return true;
60-
}
57+
6158
String username = identity.toLowerCase(Locale.US);
6259
if (stripDomain) {
6360
int p = username.indexOf('@');
@@ -67,6 +64,7 @@ public boolean validateIdentity(ServerSession session, String identity) {
6764
}
6865
UserModel user = authManager.authenticate(username);
6966
if (user != null) {
67+
// TODO: Check if the user was set in the client and if it is the same as this user. Do not allow changing the user during the SSH auth process.
7068
client.setUser(user);
7169
return true;
7270
}

src/main/java/com/gitblit/transport/ssh/UsernamePasswordAuthenticator.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,11 @@ public UsernamePasswordAuthenticator(IAuthenticationManager authManager) {
4545
@Override
4646
public boolean authenticate(String username, String password, ServerSession session) {
4747
SshDaemonClient client = session.getAttribute(SshDaemonClient.KEY);
48-
if (client.getUser() != null) {
49-
log.info("{} has already authenticated!", username);
50-
return true;
51-
}
5248

5349
username = username.toLowerCase(Locale.US);
5450
UserModel user = authManager.authenticate(username, password.toCharArray(), null);
5551
if (user != null) {
52+
// TODO: Check if the user was set in the client and if it is the same as this user. Do not allow changing the user during the SSH auth process.
5653
client.setUser(user);
5754
return true;
5855
}

src/test/java/com/gitblit/tests/SshDaemonTest.java

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616
package com.gitblit.tests;
1717

1818
import java.io.File;
19+
import java.security.KeyPair;
1920
import java.text.MessageFormat;
2021
import java.util.List;
2122

2223
import org.apache.sshd.client.SshClient;
24+
import org.apache.sshd.client.future.AuthFuture;
2325
import org.apache.sshd.client.session.ClientSession;
2426
import org.eclipse.jgit.api.CloneCommand;
2527
import org.eclipse.jgit.api.Git;
@@ -41,12 +43,73 @@ public class SshDaemonTest extends SshUnitTest {
4143

4244
String url = GitBlitSuite.sshDaemonUrl;
4345

46+
@Test
47+
public void testPasswordAuthentication() throws Exception {
48+
SshClient client = getClient();
49+
ClientSession session = client.connect(username, "localhost", GitBlitSuite.sshPort).verify().getSession();
50+
51+
session.addPasswordIdentity(password);
52+
AuthFuture authFuture = session.auth();
53+
assertTrue(authFuture.await());
54+
assertTrue(authFuture.isSuccess());
55+
}
56+
4457
@Test
4558
public void testPublicKeyAuthentication() throws Exception {
4659
SshClient client = getClient();
4760
ClientSession session = client.connect(username, "localhost", GitBlitSuite.sshPort).verify().getSession();
61+
4862
session.addPublicKeyIdentity(rwKeyPair);
49-
assertTrue(session.auth().await());
63+
AuthFuture authFuture = session.auth();
64+
assertTrue(authFuture.await());
65+
assertTrue(authFuture.isSuccess());
66+
}
67+
68+
@Test
69+
public void testWrongPublicKeyAuthentication() throws Exception {
70+
SshClient client = getClient();
71+
ClientSession session = client.connect(username, "localhost", GitBlitSuite.sshPort).verify().getSession();
72+
KeyPair attackKeyPair = generator.generateKeyPair();
73+
74+
session.addPublicKeyIdentity(attackKeyPair);
75+
AuthFuture authFuture = session.auth();
76+
assertTrue(authFuture.await());
77+
assertFalse(authFuture.isSuccess());
78+
}
79+
80+
@Test
81+
public void testWrongPublicKeyThenPasswordAuthentication() throws Exception {
82+
SshClient client = getClient();
83+
ClientSession session = client.connect(username, "localhost", GitBlitSuite.sshPort).verify().getSession();
84+
KeyPair otherKeyPair = generator.generateKeyPair();
85+
86+
session.addPublicKeyIdentity(otherKeyPair);
87+
AuthFuture authFuture = session.auth();
88+
assertTrue(authFuture.await());
89+
assertFalse(authFuture.isSuccess());
90+
91+
session.addPasswordIdentity(password);
92+
authFuture = session.auth();
93+
assertTrue(authFuture.await());
94+
assertTrue(authFuture.isSuccess());
95+
}
96+
97+
@Test
98+
public void testWrongPublicKeyThenWrongPasswordAuthentication() throws Exception {
99+
SshClient client = getClient();
100+
ClientSession session = client.connect(username, "localhost", GitBlitSuite.sshPort).verify().getSession();
101+
KeyPair otherKeyPair = generator.generateKeyPair();
102+
KeyPair attackKeyPair = new KeyPair(rwKeyPair.getPublic(), otherKeyPair.getPrivate());
103+
104+
session.addPublicKeyIdentity(attackKeyPair);
105+
AuthFuture authFuture = session.auth();
106+
assertTrue(authFuture.await());
107+
assertFalse(authFuture.isSuccess());
108+
109+
session.addPasswordIdentity("nothing");
110+
authFuture = session.auth();
111+
assertTrue(authFuture.await());
112+
assertFalse(authFuture.isSuccess());
50113
}
51114

52115
@Test

0 commit comments

Comments
 (0)