xorl %eax, %eax

OpenSSH ‘sftp-server’ Remote Security Vulnerability

with 2 comments

In the ChangeLog of OpenSSH 7.6 there is only one security fix, and I couldn’t find any associated CVE ID to it. It is basically a design flaw of sftp-server when in read-only mode. Theoretically, read-only should not allow any write operations but Michal Zalewski discovered that you can create zero-length files.

 * sftp-server(8): in read-only mode, sftp-server was incorrectly
   permitting creation of zero-length files. Reported by Michal

The vulnerability was located in sftp-server.c source code file and it affected all versions from OpenSSH 5.5 until 7.6 where it was fixed. If the SFTP server starts with the -R flag, it will enable the “readonly” variable as you can see below. This indicates that the clients are not allowed to perform and write operations.

sftp_server_main(int argc, char **argv, struct passwd *user_pw)
	while (!skipargs && (ch = getopt(argc, argv,
	    "d:f:l:P:p:Q:u:cehR")) != -1) {
		switch (ch) {
		case 'R':
			readonly = 1;

The file opening for SFTP server is performed via process_open() helper function which was opening the files for read-only mode as shown below.

static void
process_open(u_int32_t id)
	if (readonly &&
	    ((flags & O_ACCMODE) == O_WRONLY ||
	    (flags & O_ACCMODE) == O_RDWR) != 0)) {
		verbose("Refusing open request in read-only mode");
	} else {
		fd = open(name, flags, mode);

As you can see, if “readonly” flag is enabled, it will check if the opening flags “WRITE ONLY” or “READ/WRITE” exist and if this is the case it will error out with “Refusing open request in read-only mode”. Otherwise, it will open the file using open() system call. This looks correct but it doesn’t take into account other argument flags of open() system call such as O_CREAT (create file) or O_TRUNC (truncate file). Those were the flags that M. Zalewski used to create arbitrary files in a read-only SFTP server. To fix this, OpenSSH developers changed the logic of this check to ensure that it will error out if the flag is not O_RDONLY (Read-only) or it includes O_CREAT or O_TRUNC flags. You can see the patch below.

 	if (readonly &&
-	    ((flags & O_ACCMODE) == O_WRONLY ||
-	    (flags & O_ACCMODE) == O_RDWR)) {
+	    ((flags & O_ACCMODE) != O_RDONLY ||
+	    (flags & (O_CREAT|O_TRUNC)) != 0)) {
 		verbose("Refusing open request in read-only mode");

Written by xorl

November 13, 2017 at 23:08

Posted in vulnerabilities

2 Responses

Subscribe to comments with RSS.

  1. This is CVE-2017-15906

    Marcus Meissner

    November 14, 2017 at 12:22

  2. Thanks!


    November 14, 2017 at 20:22

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: