oss-sec mailing list archives

Re: Re: hwclock(8) SUID privilege escalation


From: Stephane Chazelas <stephane.chazelas () gmail com>
Date: Tue, 26 May 2015 23:21:49 +0100

2015-05-26 17:30:40 +0200, up201407890 () alunos dcc fc up pt:
[...]
No, bash does NOT drop privileges if ruid != euid when called as
sh either . If it were, it would break those commands that use
system()/popen() from suid/sgid executables (which arguably they
shouldn't be doing) and expect the euid/egid to be preserved.
[...]
I'm talking about this:

# gcc -xc - -otest <<< 'main(int argc, char *argv[]){system(argv[1]);}'
# chmod +s test
# exit
$ ls -l ./test /bin/sh
lrwxrwxrwx. 1 root root 9 May 24 11:58 /bin/sh -> /bin/bash
-rwsrwsr-x. 1 root root 8497 May 26 15:36 test
$ ./test /bin/sh
$ whoami
saken

$ su
Password:
# ln -sf /bin/dash /bin/sh
# exit
$ ./test /bin/sh
# whoami
root

I do get "root" with both dash and bash, but after
investigation, that's because I'm on a Debian based system. So
we're both right, but my version is only true on Debian.

Since 1999, Debian (and derivatives) does disable the dropping
of privileged when called as sh.
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=52586

$ cat bash-4.3/debian/patches/privmode.diff
# DP: XXX missing description
# DP:
# DP: Comment from Chet Ramey <chet () nike ins cwru edu>:
# DP:
# DP: Nope.  This will allow setuid scripts if not called as `sh' and not
# DP: called with the -p option.  I won't install this.


--- a/shell.c
+++ b/shell.c
@@ -492,7 +492,7 @@
   if (dump_translatable_strings)
     read_but_dont_execute = 1;

-  if (running_setuid && privileged_mode == 0)
+  if (running_setuid && privileged_mode == 0 && act_like_sh == 0)
     disable_priv_mode ();

   /* Need to get the argument to a -c option processed in the

(looks like from the comment, Chet misinterpreted the patch. It
will allow setuid scripts if called as sh with or without -p.
When not called as sh, you need -p to allow setuid (not drop
privileges)).

[...]
I believe that's what setuid()/seteuid()/setreuid() are for if you
really want to execute stuff as another user.

Setting setuid(0) before the system() call on my test and executing
/bin/sh (which is linked to bash) would drop me into a root shell.
This doesn't happen if there is no setuid(0) call.
The same doesn't happen when /bin/sh is linked to dash, there is no
need for setuid(0), it will drop me instantly into a root shell.
[...]

But then if you do that, the shell can no longer detect it is
called as setuid and cannot enter the privileged mode (which
disables export functions importing, BASH_ENV...).

You'd need to call sh with -p, but system()/popen() won't do
that for you.

IOW, to work around that security restriction in non-Debian
bash, one could end up doing something less safe (not only call
system() in a setuid command, but also do it in a way that
prevents the shell from taking precautions).

-- 
Stephane


Current thread: