8747333 2002-07-19 04:54 +0200  /141 rader/ FozZy <fozzy@dmpfrance.com>
Sänt av: joel@lysator.liu.se
Importerad: 2002-07-19  04:14  av Brevbäraren
Extern mottagare: bugtraq@securityfocus.com
Mottagare: Bugtraq (import) <23143>
Ärende: Linux kernel setgid implementation flaw
------------------------------------------------------------
From: FozZy <fozzy@dmpfrance.com>
To: bugtraq@securityfocus.com
Message-ID: <20020719045418.5a144713.fozzy@dmpfrance.com>

Hi,

I believe the following to be accurate and of some interest to
bugtraq  readers, although i did not have time to extensively test
it, nor did i  warn the vendor, since 1) this is at most a undirect
risk - IMHO - and 2) i am  going on holidays so i had to balance
betweeen disclosing now and letting  people think about it and patch
it OR delaying publication and forgetting it  for some months as
usual ;) But as i said, it is only a subtle local flaw  that, i
think, do not have direct security consequences in most linux
distributions. Unless someone see something i missed. Also, I
apologise if i am totally wrong here, no time to cross check it.


OVERVIEW

On current stable linux systems the setgid system call does not behave 
correctly in certain conditions:
- Setgid-only programs cannot fully drop privileges.
- Programs with both setuid and setgid flags which call
setuid(getuid) before  setgid(getgid) do not fully drop privileges.

"priviledges are not fully dropped" means that the saved gid remains
0,  although both gid, egid, fsgid, uid, euid, suid, and fsuid are
set to  the unprivileged user id.


CONSEQUENCES

A setuid or setgid program can wish to give up its privileges as soon
as it  does not need them anymore, if the program is written to
minimise the  impact of a vulnerability in the now unprivileged part
of the code. Note that  most linux set[ug]id progs seems to don't
care too much about it. Surely in  owl linux and such they care more
(and in openbsd for sure, but...).  The problem is, if a
vulnerability (like a buffer overflow) appears in an  unprivileged
part of the code, with current linux kernels the cracker will  still
be able to get group id 0 (from the saved gid) ! That is a good
launch  pad for gaining full root privileges.

Don't panic, the impact of this vulnerability is LOW in most (all ?)
linux  distributions:
- it is local only (well, unless you wrote a daemon that thinks it
can drop group privileges *after* doing the setuid(userid) ! And
unless you have a setgid daemon or network client program).
- it needs for a setgid or setuid program to have an exploitable 
vulnerability.
- it could be a serious vulnerability if security was not so low in
current  linux systems. Most set[ug]id programs do not even bother to
give up their  privileges, so locally exploiting them gives instant
root.
- Programs which drop privileges before calling execve are not
vulnerable  since exceve reset the saved uid (at least it should: not
tested).

However, if you can find on your system a program that relies too
much on the setgid behavior and gives full control to the user on the
process, this problem would become a very serious vulnerability. I
did not find any program of this type on my Mandrake systems.


DETAILS

I tested this with a 2.4.3 kernel, and the latest 2.4.18 with the
(excellent)  grsecurity patch.

From the setgid manpage (conforming to most unix systems if not all):

"If  the  user  is root or the program is setgid root, special care
must be  taken. The setgid function checks the effective gid of the
caller  and  if it is the superuser, all process related group ID's
are set to gid.  After   this has occurred, it is impossible for the
program to regain root  privi­ leges."

However: 

[fozzy@defcon10 fozzy]$ uname -a
Linux 2.4.18-grsec-1.9.4 #5 (...)
[fozzy@defcon10 fozzy]$ ls -l dg
-r-xr-sr-x    1 root     root        15525 jui 19 04:18 dg*
[fozzy@defcon10 fozzy]$ ./dg
uid=501, euid=501, gid=501, egid=0
--> suid=501 and sgid=0
Dropping privileges...
Privileges dropped : uid=501, euid=501, gid=501, egid=501
--> suid=501 and sgid=0 After trying to recover here is what we've
got: uid=501, euid=501, gid=501,  egid=0 /\/\/\/\

See the attached source code of the program.


IN-DEPTH DETAILS

Here is the interesting part of the advisory: WHY ?
Well, easy. Let's take a look at the main part of the setgid syscall:

------------------------
if (capable(CAP_SETGID))
        {
                if(old_egid != gid)
                        current->dumpable=0;
                current->gid = current->egid = current->sgid = current->fsgid 
= gid;
        }
else if ((gid == current->gid) || (gid == current->sgid))
        {
                if(old_egid != gid)
                        current->dumpable=0;
                current->egid = current->fsgid = gid;
        }
-----------------------

If the process do not have the CAP_SETGID capability, current->sgid
is  never modified ! It will remain 0 no matter what you do (well,
actually, a  setregid will change the sgid, and a setresgid also, but
everybody call the  standard setgid).  This capability is set only if
you are the superuser (unless you  have set up a real
capability-aware system of course). So it is not set when  running
setgid programs, and in setuid programs it is unset when you do a
setuid(user).

As an untested 30 seconds-reflexion patch I would suggest editing the
setgid  syscall in kernel/sys.c like this (last line in the above
source code):
 
439c439
<               current->egid = current->fsgid = gid;
---
>               current->egid = current->fsgid = current->sgid = gid;


CONCLUSION

See you in Marocco :)


FozZy
Hackademy & Hackerz Voice Director
(8747333) /FozZy <fozzy@dmpfrance.com>/---(Ombruten)
Bilaga (application/octet-stream) i text 8747334
Kommentar i text 8750476 av FozZy <fozzy@dmpfrance.com>
8747334 2002-07-19 04:54 +0200  /46 rader/ FozZy <fozzy@dmpfrance.com>
Bilagans filnamn: "drop_gid.c"
Importerad: 2002-07-19  04:14  av Brevbäraren
Extern mottagare: bugtraq@securityfocus.com
Mottagare: Bugtraq (import) <23144>
Bilaga (text/plain) till text 8747333
Ärende: Bilaga (drop_gid.c) till: Linux kernel setgid implementation flaw
------------------------------------------------------------
/* drop_gid.c - scaled down version of my [e|fs|s|][ug]id behavior checker */
/* su ; gcc -o dg drop_gid.c ; chmod 2555 dg ; su user ; ./dg */
/* The test is: can we recover some privileges after setgid() ? */
 
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#define LINUX
 
int
main (void) {
  uid_t uid, euid, suid, TARGETID;
  gid_t gid, egid, sgid;
  TARGETID=getgid();
				 
  printf("uid=%d, euid=%d, gid=%d, egid=%d\n", getuid(), geteuid(), getgid(), getegid());
#ifdef LINUX
  getresuid(&uid, &euid, &suid);
  getresgid(&gid, &egid, &sgid);
  printf("--> suid=%d and sgid=%d\n", suid, sgid);
#endif
  printf("Dropping privileges...\n");
  if (setgid(TARGETID))
    perror("setgid");
  if (setuid(TARGETID))
    perror("setuid");
  printf("Privileges dropped : uid=%d, euid=%d, gid=%d, egid=%d\n", getuid(), geteuid(), getgid(), getegid());
#ifdef LINUX
  if (getresuid(&uid, &euid, &suid))
    perror("getresuid");
  if (getresgid(&gid, &egid, &sgid))
    perror("getresgid");
  printf("--> suid=%d and sgid=%d\n", suid, sgid);
#endif
  if (setegid(0))
    perror("setegid");
  if (setfsgid(0))
    perror("setfsgid");
  if (setgid(0))
    perror("setgid");
																		 
  printf("After trying to recover here is what we've got: uid=%d,
  euid=%d, gid=%d, egid=%d\n", getuid(), geteuid(), getgid(),
  getegid());
  return 0;
}
(8747334) /FozZy <fozzy@dmpfrance.com>/---(Ombruten)
8750476 2002-07-19 14:15 +0200  /23 rader/ FozZy <fozzy@dmpfrance.com>
Sänt av: joel@lysator.liu.se
Importerad: 2002-07-19  17:59  av Brevbäraren
Extern mottagare: bugtraq@securityfocus.com
Mottagare: Bugtraq (import) <23150>
Kommentar till text 8747333 av FozZy <fozzy@dmpfrance.com>
Ärende: Re: Linux kernel setgid implementation flaw
------------------------------------------------------------
From: FozZy <fozzy@dmpfrance.com>
To: bugtraq@securityfocus.com
Message-ID: <20020719141554.694f07e1.fozzy@dmpfrance.com>

Thanks to everyone for your answers. To sum up:
- this is correct standard unix98 behavior
- the linux setgid manpage is wrong.

Hey, sorry for pointing out a vulnerability in a manpage :p

Better to know that. set*id calls are tricky. I had checked the
FreeBSD behavior, it was the same as what both linux and freebsd
manpage told: "the setgid() function sets the real and effective
group IDs and the saved set-group-ID of the current process to the
specified value", no matter what the user id is (super-user or not).

I now realize that both behaviors are acceptable: 
- FreeBSD setgid syscall is "POSIX1 compliant with _POSIX_SAVED_IDS
*not* defined with the Appendix B.4.2.2 permitted extensions".
- Linux uses more current standards (but should update its manpage;
so beware when porting FreeBSD apps to linux ;)

FozZy
Hackademy & Hackerz Voice Director

PS: Such an error in a manpage, for people (like me) who are not
standard unix98 gurus, is dangerous.  For developpers of course, but
i am also thinking about system administrators trying to set up a
more secure system by removing the setuid bit from some programs, and
tuning file permissions (and maybe hacking a bit the program) so that
the setgid bit only makes the job. I used to do that. It could
actually result in lower security !
(8750476) /FozZy <fozzy@dmpfrance.com>/---(Ombruten)
Kommentar i text 8750991 av Wietse Venema <wietse@porcupine.org>
8750991 2002-07-19 12:48 -0400  /17 rader/ Wietse Venema <wietse@porcupine.org>
Sänt av: joel@lysator.liu.se
Importerad: 2002-07-19  20:15  av Brevbäraren
Extern mottagare: bugtraq@securityfocus.com
Externa svar till: bugtraq@securityfocus.com
Mottagare: Bugtraq (import) <23153>
Kommentar till text 8750476 av FozZy <fozzy@dmpfrance.com>
Ärende: Re: Linux kernel setgid implementation flaw
------------------------------------------------------------
From: wietse@porcupine.org (Wietse Venema)
To: bugtraq@securityfocus.com
Message-ID: <20020719164849.222FCBC073@spike.porcupine.org>

FYI,

The August USENIX Security conference has a good paper that examines
in depth the semantics of UID and GID setting calls for Solaris,
FreeBSD and Linux. The differences are quite remarkable.

	Wietse

Setuid Demystified, by Hao Chen, David Wagner, UC Berkeley; Drew
Dean, SRI International
www.cs.berkeley.edu/~daw/papers/setuid-usenix02.pdf
(8750991) /Wietse Venema <wietse@porcupine.org>/----
8751372 2002-07-19 22:19 +0200  /33 rader/ FozZy <fozzy@dmpfrance.com>
Sänt av: joel@lysator.liu.se
Importerad: 2002-07-19  22:24  av Brevbäraren
Extern mottagare: bugtraq@securityfocus.com
Extern kopiemottagare: vuln-dev@securityfocus.com
Mottagare: Bugtraq (import) <23155>
Kommentar till text 8750991 av Wietse Venema <wietse@porcupine.org>
Ärende: Re: Linux kernel setgid implementation flaw
------------------------------------------------------------
From: FozZy <fozzy@dmpfrance.com>
To: bugtraq@securityfocus.com
Cc: vuln-dev@securityfocus.com
Message-ID: <20020719221939.49ab857d.fozzy@dmpfrance.com>

Thanks, it's a great paper. Unix developpers: it should be worth
taking a look at it.

Indeed, with their rigourous methodology, the authors did detect this
error in the setgid linux manpage on Red Hat 7.2. I just wonder if
they reported it (the manpage on www.linux.org is still inaccurate at
the moment).  This paper also reports a real example of a program
with the setgid flag only, that thinks it can drop all privileges by
calling setgid(getgid()). It is OK on FreeBSD, but not on Linux...

Another interesting example is a setuid program with a non-root owner
that want to drop its privileges. (I use here the word "privilege" in
an extensive and empiric "having access to objects on the system that
are forbidden to the current user"). Well, on Linux and Solaris, this
program will not properly drop privileges by the usual way: calling
setgid() then setuid(). The saved uid and gid will remain the owner's
ones.

And much more interesting stuff... :)


FozZy

On Fri, 19 Jul 2002 12:48:49 -0400 (EDT)
wietse@porcupine.org (Wietse Venema) wrote:

> FYI,
> 
> The August USENIX Security conference has a good paper that examines
> in depth the semantics of UID and GID setting calls for Solaris,
> FreeBSD and Linux. The differences are quite remarkable.
> 
> 	Wietse
> 
> Setuid Demystified, by Hao Chen, David Wagner, UC Berkeley; Drew
> Dean, SRI International
> www.cs.berkeley.edu/~daw/papers/setuid-usenix02.pdf
(8751372) /FozZy <fozzy@dmpfrance.com>/---(Ombruten)