Blob Blame History Raw
From: Russ Allbery <rra@debian.org>
Date: Thu, 17 Jan 2019 19:21:40 -0800
Subject: Verify scp command options

ESnet discovered a security vulnerability in the scp backend for
rssh.  Since the arguments to scp on the server side were not
checked, the client could pass in arbitrary scp command-line flags,
including setting arbitrary scp options.  This allows setting the
option PKCS11Provider, which loads and executes code from a shared
module.

Even if the -o flag is blocked, this is still possible via -F to
load an already-uploaded ssh configuration file, or, if .ssh/config
is writable, by just uploading that configuration file directly
first.

Attempt to protect against this attack by checking the command line
of scp and only allowing the options that are passed to the server
end of the connection.  Require either -f or -t be given, which
disables scp's attempts to connect to a remote host.  Allow these as
-pf and -pt, which are sent by libssh2.

Debian Bug#919623
---
 util.c | 44 ++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 42 insertions(+), 2 deletions(-)

diff --git a/util.c b/util.c
index dc8c8fb..4203eac 100644
--- a/util.c
+++ b/util.c
@@ -266,6 +266,43 @@ static int rsync_okay( char **vec )
 }
 
 
+/*
+ * scp_okay() - take the command line and check that it is a hopefully-safe scp
+ *		server command line, accepting only very specific options.
+ *		Returns FALSE if the command line should not be allowed, TRUE
+ *		if it is okay.
+ */
+static int scp_okay( char **vec )
+{
+	int saw_f_or_t = FALSE;
+
+	for ( vec++; vec && *vec; vec++ ){
+		/* Allowed options. */
+		if ( strcmp(*vec, "-v") == 0 ) continue;
+		if ( strcmp(*vec, "-r") == 0 ) continue;
+		if ( strcmp(*vec, "-p") == 0 ) continue;
+		if ( strcmp(*vec, "-d") == 0 ) continue;
+		if ( strcmp(*vec, "-f") == 0 || strcmp(*vec, "-pf") == 0 ){
+			saw_f_or_t = TRUE;
+			continue;
+		}
+		if ( strcmp(*vec, "-t") == 0 || strcmp(*vec, "-pt") == 0 ){
+			saw_f_or_t = TRUE;
+			continue;
+		}
+
+		/* End of arguments. */
+		if ( strcmp(*vec, "--") == 0 ) break;
+
+		/* Any other argument is not allowed. */
+		if ( *vec[0] == '-' ) return FALSE;
+	}
+
+	/* Either -f or -t must have been given. */
+	return saw_f_or_t;
+}
+
+
 /*
  * check_command_line() - take the command line passed to rssh, and verify
  *			  that the specified command is one the user is
@@ -281,8 +318,11 @@ char *check_command_line( char **cl, ShellOptions_t *opts )
 		return PATH_SFTP_SERVER;
 
 	if ( check_command(*cl, opts, PATH_SCP, RSSH_ALLOW_SCP) ){
-		/* filter -S option */
-		if ( opt_filter(cl, 'S') ) return NULL;
+		if ( !scp_okay(cl) ){
+			fprintf(stderr, "\ninsecure scp option not allowed.");
+			log_msg("insecure scp option in scp command line");
+			return NULL;
+		}
 		return PATH_SCP;
 	}