| From 88d57f10fd058f8116dd5d9a12d875885e59eb54 Mon Sep 17 00:00:00 2001 |
| From: "djm@openbsd.org" <djm@openbsd.org> |
| Date: Mon, 18 Dec 2023 14:47:44 +0000 |
| Subject: [PATCH] upstream: ban user/hostnames with most shell metacharacters |
| |
| This makes ssh(1) refuse user or host names provided on the |
| commandline that contain most shell metacharacters. |
| |
| Some programs that invoke ssh(1) using untrusted data do not filter |
| metacharacters in arguments they supply. This could create |
| interactions with user-specified ProxyCommand and other directives |
| that allow shell injection attacks to occur. |
| |
| It's a mistake to invoke ssh(1) with arbitrary untrusted arguments, |
| but getting this stuff right can be tricky, so this should prevent |
| most obvious ways of creating risky situations. It however is not |
| and cannot be perfect: ssh(1) has no practical way of interpreting |
| what shell quoting rules are in use and how they interact with the |
| user's specified ProxyCommand. |
| |
| To allow configurations that use strange user or hostnames to |
| continue to work, this strictness is applied only to names coming |
| from the commandline. Names specified using User or Hostname |
| directives in ssh_config(5) are not affected. |
| |
| feedback/ok millert@ markus@ dtucker@ deraadt@ |
| |
| OpenBSD-Commit-ID: 3b487348b5964f3e77b6b4d3da4c3b439e94b2d9 |
| --- |
| ssh.c | 39 +++++++++++++++++++++++++++++++++++++++ |
| 1 file changed, 39 insertions(+) |
| |
| diff --git a/ssh.c b/ssh.c |
| index 53330da5a..ec1eede32 100644 |
| --- a/ssh.c |
| +++ b/ssh.c |
| @@ -627,6 +627,41 @@ ssh_conn_info_free(struct ssh_conn_info *cinfo) |
| free(cinfo); |
| } |
| |
| +static int |
| +valid_hostname(const char *s) |
| +{ |
| + size_t i; |
| + |
| + if (*s == '-') |
| + return 0; |
| + for (i = 0; s[i] != 0; i++) { |
| + if (strchr("'`\"$\\;&<>|(){}", s[i]) != NULL || |
| + isspace((u_char)s[i]) || iscntrl((u_char)s[i])) |
| + return 0; |
| + } |
| + return 1; |
| +} |
| + |
| +static int |
| +valid_ruser(const char *s) |
| +{ |
| + size_t i; |
| + |
| + if (*s == '-') |
| + return 0; |
| + for (i = 0; s[i] != 0; i++) { |
| + if (strchr("'`\";&<>|(){}", s[i]) != NULL) |
| + return 0; |
| + /* Disallow '-' after whitespace */ |
| + if (isspace((u_char)s[i]) && s[i + 1] == '-') |
| + return 0; |
| + /* Disallow \ in last position */ |
| + if (s[i] == '\\' && s[i + 1] == '\0') |
| + return 0; |
| + } |
| + return 1; |
| +} |
| + |
| /* |
| * Main program for the ssh client. |
| */ |
| @@ -1107,6 +1142,10 @@ main(int ac, char **av) |
| if (!host) |
| usage(); |
| |
| + if (!valid_hostname(host)) |
| + fatal("hostname contains invalid characters"); |
| + if (options.user != NULL && !valid_ruser(options.user)) |
| + fatal("remote username contains invalid characters"); |
| host_arg = xstrdup(host); |
| |
| /* Initialize the command to execute on remote host. */ |
| -- |
| 2.43.0.472.g3155946c3a-goog |
| |