Network Attack Detection

by @im_a_muppet on March 16, 2007

For this assignment we were to modify the scavenger program to read a trace file and detect what type of attack is taking place over the network (if any).

PA3 the assignment. (project files)

pa3.c my solution

/* 
 * Will Mernagh Mar 2007 
 * PA3
 * Mar 2007
 */

#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

/* based on the background info and attack files these are the tresholds 
 * These numbers could be made better with more data 
 */
#define ALLOWED_RST 100
#define MAX_ALLOWED_IP 70
#define MAX_ALLOWED_PORTS 75
#define RESET_COUNT 500

/* linked list of ports this is needed to count the number of different ports */
typedef struct ports port_list;
struct port_list{
    int number;
    int count;
    struct port_list *next;
};

/* a linked list of hosts - for counting different hosts by IP */
typedef struct host_info host;
struct host{
    char ip_addr[20];
    struct port_list *port;
    int num_of_ports;
    int count;
    struct host *next;
};

/* an event counter. */
typedef struct tcp_flag_event_counter tcp_event_counter;
struct tcp_event_counter{
    int num_of_events;
    struct host *source;
    struct host *dest;
    int num_of_source;
    int num_of_dest;
    int num_dest_ports;
    int num_source_ports;
    int num_of_packets_less_events; /* since first event num_of_packets_less_events*/
};

/* function prototypes */
struct tcp_event_counter * check_events(struct tcphdr *tcpheader, 
                            struct ip *ipheader, struct tcp_event_counter *);
struct tcp_event_counter * parse_input(char* path, struct tcp_event_counter *);
int main(int argc, char** argv);
void decode_tcp_flags(char *buffer, int buflen, unsigned short urg, 
                      unsigned short ack, unsigned short psh, unsigned short rst, 
                      unsigned short syn, unsigned short fin);
void print_usage();
struct tcp_event_counter * increment_Event(struct tcphdr *, struct ip *, 
                                           struct tcp_event_counter *);
void free_event_nodes(struct tcp_event_counter *ig_event_counter);
void print_type_of_attack(struct tcp_event_counter *ig_event_counter);


/* function implementations */

/* check_events()
*
* This function takes in a tcphdr struct and decides if an searched for event
* occured. It just looks for RST but can be easily modified for others
*/
struct tcp_event_counter *check_events(struct tcphdr *tcpheader, 
                struct ip *ipheader, struct tcp_event_counter *ig_event_counter)
{
    char buffer[25];

    char *rst_search, *syn_search, *syn_ack_search, *buf, *result;
    char synstr[] = "SYN", rststr[] = "RST", synackstr[] = "SYN ACK"; 

    decode_tcp_flags(buffer, 25, tcpheader->urg, tcpheader->ack,  
                tcpheader->psh, tcpheader->rst, tcpheader->syn, tcpheader->fin);

    rst_search = rststr;
    syn_search = synstr;
    syn_ack_search = synackstr;
    buf = buffer;

    /* search for different types of events 
     * Type 1: Large num of RST + Small set of IPs + Large set of ports 
     * Type 2: Large num of RST + Large num of Ips + Small num of ports
     * Type 3: Large number of SYN ACK with no corresponding ACK 
     *           This type will not be checked for here because we will determin
     *           the info from RST
     */
    result = strstr(buf,rst_search);

    /* If RST increment event counter */
    if(result != NULL){
        ig_event_counter = increment_Event(tcpheader,ipheader, ig_event_counter);
    }

    return ig_event_counter;
}


/* decode_tcp_flags()
*
* This function takes in all the flags from a tcp struct and prints
* which flags are set as a string.  It outputs the string to the 
* buffer parameter.  This buffer needs to be at least 25 chars in length.
*/
void decode_tcp_flags(char *buffer, 
                      int buflen,
                      unsigned short urg, 
                      unsigned short ack, 
                      unsigned short psh, 
                      unsigned short rst, 
                      unsigned short syn, 
                      unsigned short fin)
{
    int index = 0;

    bzero(buffer, buflen);        // clear buffer

    if (syn) {
        sprintf(index + buffer, "SYN ");
        index += 4;
    }

    if (urg) {
        sprintf(buffer, "URG ");
        index += 4;
    }

    if (ack) {
        sprintf(index + buffer, "ACK ");
        index += 4;
    }

    if (psh) {
        sprintf(index + buffer, "PSH ");
        index += 4;
    }

    if (rst) {
        sprintf(index + buffer, "RST ");
        index += 4;
    }

    if (fin) {
        sprintf(index + buffer, "FIN ");
        index += 4;
    }
}


/* parse_input()
 *
 * Given the trace file name and path, opens the file and reads in the 
 * data line by line.  Each line corresponds to one packet, so the hex
 * characters in each line are converted to an array of binary values.
 * The ip and tcphdr structs are applied to the data array, 
 */
struct tcp_event_counter *parse_input(char* path, 
                                    struct tcp_event_counter *ig_event_counter)
{
    FILE *tracefile = NULL;
    char *line, *curr;
    size_t nbytes = 400;
    ssize_t bytes_read;
    int packetnum, input2;
    unsigned short shortarr[66000];        // max packet length is 2^16
    int count;
    struct ip *ipheader;
    struct tcphdr *tcpheader;

    /* open file for reading */
    tracefile = fopen(path, "r");

    if (tracefile == NULL)
    {
        printf("Error: input file %s not found\n", path);
        exit(1);
    }

    /* allocate buffer space */
    line = (char *)malloc(nbytes + 1);

    /* input loop */
    while (1)
    {
        bytes_read = getline(&line, &nbytes, tracefile);
        if (bytes_read > 0)
        {
            count = 0;
    
            /* only parse valid data */
    
            char ok_chars[] = "0123456789 abcdef ABCDEF";
            /* minus 2 for end of file and end of line */
            if ((strspn(line, ok_chars)) < strlen(line)-2){
                printf("Error: Invalid file. ");
                printf("The file should only contain hex and white spaces\n");
                exit(1); 
            }
    
            /* get rid of line number */
            curr = strtok(line, " ");
            sscanf(curr, "%d", &packetnum);
    
            while ((curr = strtok(NULL, " ")) != NULL) {
        
                /* translate line into array of 16-bit values */
                sscanf(curr, "%x", &input2);
        
                /* put input into network byte order.  we do this so we can
                * use the helper functions defined in the netinet
                * package. */
                shortarr[count] = htons((unsigned short)input2);
                count++;
        
            }
    
            /* process short array */
            ipheader = (struct ip *)shortarr;
            tcpheader = (struct tcphdr *)(shortarr + (ipheader->ip_hl * 2));
    
            /* We only want TCP packets */
            if (ipheader->ip_p == IPPROTO_TCP) {
        
        
                /* check for RST events */
                ig_event_counter = check_events(tcpheader, ipheader, 
                                                ig_event_counter);
                /* after first RST count all packets */
                if(ig_event_counter != NULL){
                    ig_event_counter->num_of_packets_less_events++;
                }
                
                if(ig_event_counter != NULL){
            
                    /* if RST went over limit */
                    if((ig_event_counter->num_of_events) > ALLOWED_RST){
                
                        /* print type of attack (if one) */
                        print_type_of_attack(ig_event_counter);
                        /* clean up */
                        fclose(tracefile);
                        free(line);
                        return ig_event_counter;
                
                    /* if enough good events then clear RST counter */    
                    }else if(ig_event_counter->num_of_packets_less_events > RESET_COUNT){
                        free_event_nodes(ig_event_counter);
                        ig_event_counter = NULL;
                    }
                
                }
        
            }
        } else {
            break;
        }
    }

    /* clean up */
    fclose(tracefile);
    free(line);
    /* if no detected attack free counter */
    free_event_nodes(ig_event_counter);
    return ig_event_counter;
}

/* print_usage()
 *
 * Prints usage information for the program to stdout
 */
void print_usage()
{
    printf("Usage: attackalarm FILE\n\n");
}

/* main()
 *
 * Checks arguments, sets options, and does the work.
 */
int main(int argc, char** argv)
{
    char *infilename = NULL;
    int i;
    struct tcp_event_counter *ig_event_counter;
    ig_event_counter = NULL; 

    /* check for at least 1 command-line option */
    if (argc < 2) 
    {
        printf("Error: required parameter missing\n");
        print_usage();
        exit(1);
    }


    // assume this is the input filename
    if (!infilename) {
        infilename = argv[1];
    } else {
        printf("Error: unexpected argument: %s\n", argv[i]);
        print_usage();
        exit(1);
    }

    if (!infilename) 
    {
        printf("Error: required parameter missing\n");
        print_usage();
        exit(1);
    }

    /* parse input and count events */
    ig_event_counter = parse_input(infilename, ig_event_counter);

    if(ig_event_counter == NULL){
        printf("No scan detected\n");
    }else{
        /* free the event counter */
        free_event_nodes(ig_event_counter);
    }

    return 0; 
}

/* If we get a EVENT this fun gets called and increments the relavant info
 * 
 *
 */
struct tcp_event_counter *increment_Event(struct tcphdr *tcpheader, 
                                    struct ip *ipheader, 
                                    struct tcp_event_counter *event_counter){

    struct host *stored_host;
    struct port_list *port;
    int type; /* 0 = source, 1 = dest */

    /* initialize rstcounter  */
    if(event_counter == NULL){
        event_counter = (struct tcp_event_counter *)malloc
                                (sizeof(struct tcp_event_counter));
        if(event_counter == NULL){
            printf("Error: malloc\n");
            exit(1);
        }
        event_counter->num_of_source = 1;
        event_counter->num_of_dest = 1;
        event_counter->num_of_events = 1;

        event_counter->source = (struct host *)malloc(sizeof(struct host));

        if(event_counter->source == NULL){
            printf("Error: malloc\n");
            exit(1);
        }

        event_counter->source->num_of_ports = 1;
        event_counter->source->count = 1;
        event_counter->source->port = (struct port_list *)malloc
                                                    (sizeof(struct port_list));

        if(event_counter->source->port == NULL){
            printf("Error: malloc\n");
            exit(1);
        }

        strncpy(event_counter->source->ip_addr, inet_ntoa(ipheader->ip_src), 
                                        strlen(inet_ntoa(ipheader->ip_src)));
        event_counter->source->port->number = (int)ntohs(tcpheader->source);
        event_counter->source->port->count = 1;
        event_counter->source->port->next = NULL;
        event_counter->num_source_ports = 1;

        event_counter->dest = (struct host *)malloc(sizeof(struct host));

        if(event_counter->dest == NULL){
            printf("Error: malloc\n");
            exit(1);
        }

        event_counter->dest->num_of_ports = 1;
        event_counter->dest->count = 1;
        event_counter->dest->port = (struct port_list *)malloc(sizeof
                                                            (struct port_list));

        if(event_counter->dest->port == NULL){
            printf("Error: malloc\n");
            exit(1);
        }

        strncpy(event_counter->dest->ip_addr, inet_ntoa(ipheader->ip_dst), 
                                        strlen(inet_ntoa(ipheader->ip_dst)));
        event_counter->dest->port->number = (int)ntohs(tcpheader->dest);
        event_counter->dest->port->next = NULL;        
        event_counter->dest->port->count = 1;
        event_counter->num_dest_ports = 1;


        event_counter->num_of_packets_less_events = 0;
                                                     
    }else{

        event_counter->num_of_events++;
        char *current_ip;
        int current_port;

        for(type = 0; type < 2; type++){
            if(type == 0){
                stored_host = event_counter->source;
                current_ip = inet_ntoa(ipheader->ip_src);
                current_port = (int)ntohs(tcpheader->source);
            }else{
                stored_host = event_counter->dest;
                current_ip = inet_ntoa(ipheader->ip_dst);
                current_port = (int)ntohs(tcpheader->dest);
            }
     
            /* check if we have source and increment it if we do */
            //printf("Is %s == \n", current_ip);
            while(stored_host != NULL){

                /* check against current */
                if(strncmp(current_ip, stored_host->ip_addr, strlen(
                                                stored_host->ip_addr)) == 0){

                    stored_host->count++;
                    port = stored_host->port;
            
                    /* if we have source check if we have port */
                    while(port != NULL){
                        if(port->number == current_port){
                            port->count++;
                            break;
                        }else if(port->next == NULL){
                            /* keep count of ports */
                            if(type == 0){
                                event_counter->num_source_ports++;
                            }else{
                                event_counter->num_dest_ports++;
                            }
                            port->next = (struct port_list *)malloc 
                                                    (sizeof(struct port_list));
                    
                            port = port->next;
                            port->next = NULL; /* don't know why I need this */
                            if(port == NULL){
                                printf("Error: malloc\n");
                                exit(1);
                            }
                            port->number = current_port;
                            port->count = 1;
                            stored_host->num_of_ports++;
                            break;
                        }else{
                            port = port->next;
                        }
                
                    }
            
                    stored_host = stored_host->next;
                    break;
                   
                /* if new source then store it */
                }else if(stored_host->next == NULL) {
            
                    if(type == 0){
                        event_counter->num_of_source++;
                    }else{
                        event_counter->num_of_dest++;
                    }
            
                    stored_host->next = (struct host *)malloc(sizeof(
                                                                struct host));
                    stored_host = stored_host->next;
            
                    if(stored_host == NULL){
                        printf("Error: malloc\n");
                        exit(1);
                    }
            
                    stored_host->num_of_ports = 1;
                    stored_host->count = 1;
                    stored_host->port = (struct port_list *)malloc(sizeof(
                                                            struct port_list));
            
                    if(stored_host->port == NULL){
                        printf("Error: malloc\n");
                        exit(1);
                    }
            
                    strncpy(stored_host->ip_addr, current_ip, strlen(
                                                                current_ip));
                    stored_host->port->number = current_port;
                    stored_host->port->count = 1;
                    stored_host->port->next = NULL;                    
            
                    stored_host->next = NULL; /* Don't know why */
                    break;
            
                }else{
                    stored_host = stored_host->next;
                }
            }
        } /* for loop */
                
    }
    return event_counter;

}


/* This needs to recurse through the linked lists and free the memory */
void free_event_nodes(struct tcp_event_counter *ig_event_counter){
    struct host *source, *source_free, *dest, *dest_free;
    struct port_list *port, *port_free;

    if(ig_event_counter != NULL){

        dest = ig_event_counter->dest;

        while(dest != NULL){

            port = dest->port;
    
            while(port != NULL){
        
                port_free = port;
                port = port->next;
                free(port_free);
        
            }
    
            dest_free = dest;
            dest = dest->next;
            free(dest_free);
        }

        source = ig_event_counter->source;

        while(source != NULL){
    
            port = source->port;
    
            while(port != NULL){
        
                port_free = port;
                port = port->next;
                free(port_free);
        
            }
    
            source_free = source;
            source = source->next;
            free(source_free);
        }

        free(ig_event_counter);
    }

}


void print_type_of_attack(struct tcp_event_counter *ig_event_counter){

    int count = 0;
    struct host *source, *source_itr, *dest, *dest_itr;

        source_itr = ig_event_counter->source;
        source = source_itr;

        while(source_itr != NULL){
    
            /* find largest source creating event */
            if(source->count < source_itr->count){
                source = source_itr;
            }
    
            source_itr = source_itr->next;
            count++;
        }

        dest_itr = ig_event_counter->dest;
        dest = dest_itr;

        while(dest_itr != NULL){
    
            /* find largest source creating event */
            if(dest->count < dest_itr->count){
                dest = dest_itr;
            }
    
            dest_itr = dest_itr->next;
            count++;
        }
            
        /* check for port scan */
        if(source->num_of_ports > MAX_ALLOWED_PORTS && ig_event_counter->num_of_dest < MAX_ALLOWED_IP){
    
            printf("Port scan detected!\n");
            printf("Source host: %s\n", dest->ip_addr);
            printf("Destination host: %s\n", source->ip_addr);
    
        /* check for SYN flood to closed port */    
        }else if(ig_event_counter->num_of_dest > MAX_ALLOWED_IP){
    
            printf("SYN flood detected!\n");
            printf("Source host: spoofed\n");
            printf("Destination host: %s\n", source->ip_addr);
    
        /* check for SYN Flood to open port */
        }else if(ig_event_counter->num_of_source > MAX_ALLOWED_IP){
    
            printf("SYN flood detected!\n");
            printf("Source host: spoofed\n");
            printf("Destination host: %s\n", dest->ip_addr);
    
        }

}
blog comments powered by Disqus
Tweet