Resolves: RHEL-213033 Resolves: RHEL-213041 Resolves: RHEL-213047 Resolves: RHEL-213081 Resolves: RHEL-213114 Resolves: RHEL-213119 Resolves: RHEL-213151
318 lines
10 KiB
Diff
318 lines
10 KiB
Diff
From d18c05327e8a6e9e8f7ddb26021a4fb7860e4afd Mon Sep 17 00:00:00 2001
|
|
From: Norbert Pocs <norbertpocs0@gmail.com>
|
|
Date: Wed, 27 Dec 2023 20:32:18 +0100
|
|
Subject: [PATCH 04/12] misc: Add function to check username syntax
|
|
|
|
Malicious code can be injected using the username with metacharacters,
|
|
therefore the username must be validated before using it with any %u.
|
|
|
|
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
|
|
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
|
|
---
|
|
include/libssh/misc.h | 1 +
|
|
src/misc.c | 32 ++++++++++++++++++++++++++++++++
|
|
tests/unittests/torture_misc.c | 34 ++++++++++++++++++++++++++++++++++
|
|
3 files changed, 67 insertions(+)
|
|
|
|
diff --git a/include/libssh/misc.h b/include/libssh/misc.h
|
|
index 3452251d..06c62678 100644
|
|
--- a/include/libssh/misc.h
|
|
+++ b/include/libssh/misc.h
|
|
@@ -103,6 +103,7 @@ int ssh_tmpname(char *template);
|
|
char *ssh_strreplace(const char *src, const char *pattern, const char *repl);
|
|
|
|
int ssh_check_hostname_syntax(const char *hostname);
|
|
+int ssh_check_username_syntax(const char *username);
|
|
|
|
FILE *ssh_strict_fopen(const char *filename, size_t max_file_size);
|
|
|
|
diff --git a/src/misc.c b/src/misc.c
|
|
index 0cca373a..0389ee70 100644
|
|
--- a/src/misc.c
|
|
+++ b/src/misc.c
|
|
@@ -2148,4 +2148,36 @@ FILE *ssh_strict_fopen(const char *filename, size_t max_file_size)
|
|
return f;
|
|
}
|
|
|
|
+/**
|
|
+ * @brief Checks syntax of a username
|
|
+ *
|
|
+ * This check disallows metacharacters in the username
|
|
+ *
|
|
+ * @param username The username to be checked, has to be null terminated
|
|
+ *
|
|
+ * @return SSH_OK if the username passes syntax check
|
|
+ * SSH_ERROR otherwise or if username is NULL or empty string
|
|
+ */
|
|
+int ssh_check_username_syntax(const char *username)
|
|
+{
|
|
+ size_t username_len;
|
|
+
|
|
+ if (username == NULL || *username == '-') {
|
|
+ return SSH_ERROR;
|
|
+ }
|
|
+
|
|
+ username_len = strlen(username);
|
|
+ if (username_len == 0 || username[username_len - 1] == '\\' ||
|
|
+ strpbrk(username, "'`\";&<>|(){}") != NULL) {
|
|
+ return SSH_ERROR;
|
|
+ }
|
|
+ for (size_t i = 0; i < username_len; i++) {
|
|
+ if (isspace(username[i]) != 0 && username[i + 1] == '-') {
|
|
+ return SSH_ERROR;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return SSH_OK;
|
|
+}
|
|
+
|
|
/** @} */
|
|
diff --git a/tests/unittests/torture_misc.c b/tests/unittests/torture_misc.c
|
|
index 4470c358..7c134304 100644
|
|
--- a/tests/unittests/torture_misc.c
|
|
+++ b/tests/unittests/torture_misc.c
|
|
@@ -839,6 +839,39 @@ static void torture_ssh_check_hostname_syntax(void **state)
|
|
assert_int_equal(rc, SSH_ERROR);
|
|
}
|
|
|
|
+static void torture_ssh_check_username_syntax(void **state) {
|
|
+ int rc;
|
|
+ (void)state;
|
|
+
|
|
+ rc = ssh_check_username_syntax("username");
|
|
+ assert_int_equal(rc, SSH_OK);
|
|
+ rc = ssh_check_username_syntax("Alice");
|
|
+ assert_int_equal(rc, SSH_OK);
|
|
+ rc = ssh_check_username_syntax("Alice and Bob");
|
|
+ assert_int_equal(rc, SSH_OK);
|
|
+ rc = ssh_check_username_syntax("n4me?");
|
|
+ assert_int_equal(rc, SSH_OK);
|
|
+
|
|
+ rc = ssh_check_username_syntax("alice&bob");
|
|
+ assert_int_equal(rc, SSH_ERROR);
|
|
+ rc = ssh_check_username_syntax("backslash\\");
|
|
+ assert_int_equal(rc, SSH_ERROR);
|
|
+ rc = ssh_check_username_syntax("&var|()us\"<ha`r{}'");
|
|
+ assert_int_equal(rc, SSH_ERROR);
|
|
+ rc = ssh_check_username_syntax(" -");
|
|
+ assert_int_equal(rc, SSH_ERROR);
|
|
+ rc = ssh_check_username_syntax("me and -");
|
|
+ assert_int_equal(rc, SSH_ERROR);
|
|
+ rc = ssh_check_username_syntax("los -santos");
|
|
+ assert_int_equal(rc, SSH_ERROR);
|
|
+ rc = ssh_check_username_syntax("- who?");
|
|
+ assert_int_equal(rc, SSH_ERROR);
|
|
+ rc = ssh_check_username_syntax(NULL);
|
|
+ assert_int_equal(rc, SSH_ERROR);
|
|
+ rc = ssh_check_username_syntax("");
|
|
+ assert_int_equal(rc, SSH_ERROR);
|
|
+}
|
|
+
|
|
static void torture_ssh_is_ipaddr(void **state) {
|
|
int rc;
|
|
char *interf = malloc(64);
|
|
@@ -932,6 +965,7 @@ int torture_run_tests(void) {
|
|
cmocka_unit_test(torture_ssh_strreplace),
|
|
cmocka_unit_test(torture_ssh_strerror),
|
|
cmocka_unit_test(torture_ssh_check_hostname_syntax),
|
|
+ cmocka_unit_test(torture_ssh_check_username_syntax),
|
|
cmocka_unit_test(torture_ssh_is_ipaddr),
|
|
cmocka_unit_test(torture_ssh_get_hexa),
|
|
};
|
|
--
|
|
2.54.0
|
|
|
|
From b32217c6ed3a5a47e42f89fb68fe7ffec2c8f4bb Mon Sep 17 00:00:00 2001
|
|
From: Norbert Pocs <norbertpocs0@gmail.com>
|
|
Date: Thu, 28 Dec 2023 12:16:29 +0100
|
|
Subject: [PATCH 05/12] Check any input username for validity
|
|
|
|
Check possible inputs of username for malicious code.
|
|
|
|
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
|
|
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
|
|
---
|
|
src/config_parser.c | 4 ++++
|
|
src/misc.c | 10 ++++++++--
|
|
src/options.c | 5 +++++
|
|
3 files changed, 17 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/src/config_parser.c b/src/config_parser.c
|
|
index 5555f6fd..9163d374 100644
|
|
--- a/src/config_parser.c
|
|
+++ b/src/config_parser.c
|
|
@@ -203,6 +203,10 @@ int ssh_config_parse_uri(const char *tok,
|
|
if (*username == NULL) {
|
|
goto error;
|
|
}
|
|
+ rc = ssh_check_username_syntax(*username);
|
|
+ if (rc != SSH_OK) {
|
|
+ goto error;
|
|
+ }
|
|
}
|
|
tok = endp + 1;
|
|
/* If there is second @ character, this does not look like our URI */
|
|
diff --git a/src/misc.c b/src/misc.c
|
|
index 0389ee70..b63b5521 100644
|
|
--- a/src/misc.c
|
|
+++ b/src/misc.c
|
|
@@ -183,6 +183,7 @@ char *ssh_get_local_username(void)
|
|
{
|
|
DWORD size = 0;
|
|
char *user;
|
|
+ int rc;
|
|
|
|
/* get the size */
|
|
GetUserName(NULL, &size);
|
|
@@ -193,7 +194,10 @@ char *ssh_get_local_username(void)
|
|
}
|
|
|
|
if (GetUserName(user, &size)) {
|
|
- return user;
|
|
+ rc = ssh_check_username_syntax(user);
|
|
+ if (rc == SSH_OK) {
|
|
+ return user;
|
|
+ }
|
|
}
|
|
|
|
return NULL;
|
|
@@ -337,8 +341,10 @@ char *ssh_get_local_username(void)
|
|
}
|
|
|
|
name = strdup(pwd.pw_name);
|
|
+ rc = ssh_check_username_syntax(name);
|
|
|
|
- if (name == NULL) {
|
|
+ if (rc != SSH_OK) {
|
|
+ free(name);
|
|
return NULL;
|
|
}
|
|
|
|
diff --git a/src/options.c b/src/options.c
|
|
index a8023fbf..a40459ff 100644
|
|
--- a/src/options.c
|
|
+++ b/src/options.c
|
|
@@ -662,6 +662,11 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
|
|
ssh_set_error_oom(session);
|
|
return -1;
|
|
}
|
|
+ rc = ssh_check_username_syntax(session->opts.username);
|
|
+ if (rc != SSH_OK) {
|
|
+ ssh_set_error_invalid(session);
|
|
+ return -1;
|
|
+ }
|
|
}
|
|
break;
|
|
case SSH_OPTIONS_SSH_DIR:
|
|
--
|
|
2.54.0
|
|
|
|
From 26ae62df976dfd381b72f201ed4281530cd63d86 Mon Sep 17 00:00:00 2001
|
|
From: Norbert Pocs <norbertpocs0@gmail.com>
|
|
Date: Thu, 28 Dec 2023 12:27:31 +0100
|
|
Subject: [PATCH 06/12] torture: Add cases for username checks
|
|
|
|
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
|
|
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
|
|
---
|
|
tests/unittests/torture_config.c | 3 +++
|
|
tests/unittests/torture_options.c | 6 ++++++
|
|
2 files changed, 9 insertions(+)
|
|
|
|
diff --git a/tests/unittests/torture_config.c b/tests/unittests/torture_config.c
|
|
index 6dc59e48..09c769b9 100644
|
|
--- a/tests/unittests/torture_config.c
|
|
+++ b/tests/unittests/torture_config.c
|
|
@@ -2293,6 +2293,9 @@ static void torture_config_parse_uri(void **state)
|
|
assert_null(username);
|
|
assert_string_equal(hostname, "1:2:3::4");
|
|
SAFE_FREE(hostname);
|
|
+
|
|
+ rc = ssh_config_parse_uri("user -name@", &username, NULL, NULL, true);
|
|
+ assert_int_equal(rc, SSH_ERROR);
|
|
}
|
|
|
|
/* Invalid configuration files
|
|
diff --git a/tests/unittests/torture_options.c b/tests/unittests/torture_options.c
|
|
index 2a7a04de..5c3d3f2c 100644
|
|
--- a/tests/unittests/torture_options.c
|
|
+++ b/tests/unittests/torture_options.c
|
|
@@ -89,6 +89,9 @@ static void torture_options_set_host(void **state) {
|
|
assert_non_null(session->opts.username);
|
|
assert_string_equal(session->opts.username, "at@login");
|
|
|
|
+ /* disallow metacharacters in the username */
|
|
+ rc = ssh_options_set(session, SSH_OPTIONS_HOST, "shallN()tP4ss -@hostname");
|
|
+ assert_ssh_return_code_equal(session, rc, SSH_ERROR);
|
|
}
|
|
|
|
static void torture_options_set_ciphers(void **state) {
|
|
@@ -396,6 +399,9 @@ static void torture_options_set_user(void **state) {
|
|
assert_true(rc == 0);
|
|
#endif /* _WIN32 */
|
|
|
|
+ rc = ssh_options_set(session, SSH_OPTIONS_USER, "&shallN()tP4ss");
|
|
+ assert_ssh_return_code_equal(session, rc, SSH_ERROR);
|
|
+
|
|
rc = ssh_options_set(session, SSH_OPTIONS_USER, "guru");
|
|
assert_true(rc == 0);
|
|
assert_string_equal(session->opts.username, "guru");
|
|
--
|
|
2.54.0
|
|
|
|
From 08a4f4c5151e75eda6d2105db493aa8c8df0dee7 Mon Sep 17 00:00:00 2001
|
|
From: Jakub Jelen <jjelen@redhat.com>
|
|
Date: Thu, 2 Apr 2026 15:39:25 +0200
|
|
Subject: [PATCH 07/12] CVE-2026-59846 Block shell metacharacters from
|
|
usernames
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
When an attacker could sneak the dollar sign or backslash into the username
|
|
expanded for example in proxy command, it can result in printing environment
|
|
variables that might contain secrets.
|
|
|
|
This is a fixup of CVE-2023-6004 which fixed this for hostnames, but these
|
|
two metacharacters were left out from the username filter.
|
|
|
|
This keeps the list in one place to simplify maintenance.
|
|
|
|
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
|
|
Reviewed-by: Pavol Žáčik <pzacik@redhat.com>
|
|
(cherry picked from commit 6309df220e3431deb41946f892f4bb5af8b59dba)
|
|
---
|
|
include/libssh/priv.h | 2 ++
|
|
src/misc.c | 2 +-
|
|
2 files changed, 3 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/include/libssh/priv.h b/include/libssh/priv.h
|
|
index 876ea4ed..22f1e6da 100644
|
|
--- a/include/libssh/priv.h
|
|
+++ b/include/libssh/priv.h
|
|
@@ -223,6 +223,8 @@ int ssh_gettimeofday(struct timeval *__p, void *__t);
|
|
# define LIBSSH_MEM_PROTECTION
|
|
#endif
|
|
|
|
+#define SSH_DANGEROUS_SHELL_CHARS "'`\";&<>|(){}$\\,"
|
|
+
|
|
/* forward declarations */
|
|
struct ssh_common_struct;
|
|
struct ssh_kex_struct;
|
|
diff --git a/src/misc.c b/src/misc.c
|
|
index b63b5521..f4f48a37 100644
|
|
--- a/src/misc.c
|
|
+++ b/src/misc.c
|
|
@@ -2174,7 +2174,7 @@ int ssh_check_username_syntax(const char *username)
|
|
|
|
username_len = strlen(username);
|
|
if (username_len == 0 || username[username_len - 1] == '\\' ||
|
|
- strpbrk(username, "'`\";&<>|(){}") != NULL) {
|
|
+ strpbrk(username, SSH_DANGEROUS_SHELL_CHARS) != NULL) {
|
|
return SSH_ERROR;
|
|
}
|
|
for (size_t i = 0; i < username_len; i++) {
|
|
--
|
|
2.54.0
|
|
|