summaryrefslogtreecommitdiff
path: root/add-strict-scp-check-for-CVE-2020-15778.patch
blob: 3c3109c6952d99436871a66478526c5684bebe92 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
From 2e0b74242220a97926d006719d1ac6e113918e2b Mon Sep 17 00:00:00 2001
From: seuzw <930zhaowei@163.com>
Date: Thu, 20 May 2021 20:23:30 +0800
Subject: [PATCH] add strict-scp-check for CVE-2020-15778

---
 servconf.c | 12 ++++++++++++
 servconf.h |  1 +
 session.c  | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 64 insertions(+)

diff --git a/servconf.c b/servconf.c
index 333b802..0a7cfa4 100644
--- a/servconf.c
+++ b/servconf.c
@@ -91,6 +91,7 @@ initialize_server_options(ServerOptions *options)
 {
 	memset(options, 0, sizeof(*options));
 
+	options->strict_scp_check = -1;
 	/* Portable-specific options */
 	options->use_pam = -1;
 
@@ -309,6 +310,8 @@ fill_default_server_options(ServerOptions *options)
 		    _PATH_HOST_XMSS_KEY_FILE, 0);
 #endif /* WITH_XMSS */
 	}
+	if (options->strict_scp_check == -1)
+		options->strict_scp_check = 0;
 	/* No certificates by default */
 	if (options->num_ports == 0)
 		options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
@@ -516,6 +519,7 @@ fill_default_server_options(ServerOptions *options)
 /* Keyword tokens. */
 typedef enum {
 	sBadOption,		/* == unknown option */
+	sStrictScpCheck,
 	/* Portable-specific options */
 	sUsePAM,
 	/* Standard Options */
@@ -573,6 +577,7 @@ static struct {
 #else
 	{ "usepam", sUnsupported, SSHCFG_GLOBAL },
 #endif
+	{ "strictscpcheck", sStrictScpCheck, SSHCFG_GLOBAL },
 	{ "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
 	/* Standard Options */
 	{ "port", sPort, SSHCFG_GLOBAL },
@@ -1391,6 +1396,11 @@ process_server_config_line_depth(ServerOptions *options, char *line,
 	/* Standard Options */
 	case sBadOption:
 		goto out;
+
+	case sStrictScpCheck:
+		intptr = &options->strict_scp_check;
+		goto parse_flag;
+
 	case sPort:
 		/* ignore ports from configfile if cmdline specifies ports */
 		if (options->ports_from_cmdline) {
@@ -2666,6 +2676,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
 		dst->n = src->n; \
 } while (0)
 
+	M_CP_INTOPT(strict_scp_check);
 	M_CP_INTOPT(password_authentication);
 	M_CP_INTOPT(gss_authentication);
 	M_CP_INTOPT(pubkey_authentication);
@@ -2960,6 +2971,7 @@ dump_config(ServerOptions *o)
 #ifdef USE_PAM
 	dump_cfg_fmtint(sUsePAM, o->use_pam);
 #endif
+	dump_cfg_fmtint(sStrictScpCheck, o->strict_scp_check);
 	dump_cfg_int(sLoginGraceTime, o->login_grace_time);
 	dump_cfg_int(sX11DisplayOffset, o->x11_display_offset);
 	dump_cfg_int(sX11MaxDisplays, o->x11_max_displays);
diff --git a/servconf.h b/servconf.h
index cb73d2d..12c2053 100644
--- a/servconf.h
+++ b/servconf.h
@@ -203,6 +203,7 @@ typedef struct {
 					 * disconnect the session
 					 */
 
+	int     strict_scp_check;
 	u_int	num_authkeys_files;	/* Files containing public keys */
 	char   **authorized_keys_files;
 
diff --git a/session.c b/session.c
index dfbebba..1b67393 100644
--- a/session.c
+++ b/session.c
@@ -175,6 +175,51 @@ static char *auth_sock_dir = NULL;
 
 /* removes the agent forwarding socket */
 
+
+int scp_check(const char *command)
+{
+	debug("Entering scp check");
+	int check = 0;
+	if (command == NULL) {
+		debug("scp check succeeded for shell mode");
+		return check;
+	}
+	int lc = strlen(command);
+	char special_characters[] = "|;&$><`\\!\n";
+	int ls = strlen(special_characters);
+	int count_char[128] = {0};
+
+	for (int i = 0; i < ls; i++) {
+		count_char[special_characters[i]] = 1;
+	}
+
+	char scp_prefix[6] = "scp -";
+	int lp = 5;
+
+	if (lc <= lp) {
+		debug("scp check succeeded for length");
+		return check;
+	}
+
+	for (int i = 0; i < lp; i++) {
+		if (command[i] - scp_prefix[i]) {
+			debug("scp check succeeded for prefix");
+		return check;
+		}
+	}
+
+	for (int i = lp; i < lc; i++) {
+		if (command[i] > 0 && command[i] < 128) {
+			if (count_char[command[i]]) {
+				check = 1;
+				debug("scp check failed at %d: %c", i, command[i]);
+				break;
+			}
+		}
+	}
+	return check;
+}
+
 static void
 auth_sock_cleanup_proc(struct passwd *pw)
 {
@@ -692,6 +737,12 @@ do_exec(struct ssh *ssh, Session *s, const char *command)
 		command = auth_opts->force_command;
 		forced = "(key-option)";
 	}
+
+	if (options.strict_scp_check && scp_check(command)) {
+		verbose("Special characters not allowed in scp");
+		return 1;
+	}
+
 #ifdef GSSAPI
 #ifdef KRB5 /* k5users_allowed_cmds only available w/ GSSAPI+KRB5 */
 	else if (k5users_allowed_cmds) {
-- 
1.8.3.1