/* * 5n0r7.c - a snort alert file parser * Copyright (C) 2000 Michel "MaXX" Kaempf * * 5n0r7 is a snort alert file parser. It sorts the alerts on source IP, * destination IP and frequency to stdout. It is not intended to support * the portscan preprocessor which messes up snort's alert files. 5n0r7 * allows to detect attacks (portscans, probes, or whatever snort logs), * at the first sight when displaying a sorted alert file (typical usage : * `./5n0r7 ./alert'). Here is an example of 5n0r7's output : * * * a.b.c.d (21242) * - x.y.z.t (1242) * [**] NULL Scan [**] (212) * 04/18-14:10:01.504832 * srcport min/max = 62825/62826 * dstport min/max = 1/65301 * * The computer a.b.c.d triggered 21242 times the snort alert mechanism, * and 1242 of these attacks were directed to the computer x.y.z.t. * Among these attacks were 212 NULL Scan packets, and the first NULL Scan * packet was logged at 04/18-14:10:01.504832. The lowest port that sent * these NULL Scan packets is 62825, the highest is 62826. The lowest port * on x.y.z.t hit by this NULL Scan is 1, the highest is 65301 (a typical * NMAP NULL Scan). * * I recommend the use of snort's scan-lib rules and Jim Forster's excellent * rules (http://www.rapidnet.com). * * 5n0r7.c is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #define HASHSIZE 12 #define IPADDRSIZE 15 /***************************************************************************** * struct snort_nlist *****************************************************************************/ struct snort_nlist { struct snort_nlist * next; char * p_char; unsigned int ui_n; void * p; }; /***************************************************************************** * struct snort_src *****************************************************************************/ struct snort_src { struct snort_nlist * dst_hashtab[ HASHSIZE ]; }; /***************************************************************************** * struct snort_dst *****************************************************************************/ struct snort_dst { struct snort_nlist * msg_hashtab[ HASHSIZE ]; }; /***************************************************************************** * struct snort_msg *****************************************************************************/ struct snort_msg { char * pc_timestamp; unsigned int ui_srcminport, ui_srcmaxport; unsigned int ui_dstminport, ui_dstmaxport; }; /***************************************************************************** * struct snort_file *****************************************************************************/ struct snort_file { FILE * p_file; int i_bufsize; char * pc_buffer; }; /***************************************************************************** * snort_swap() *****************************************************************************/ void snort_swap( struct snort_nlist * v[], int i, int j ) { struct snort_nlist * temp; temp = v[i]; v[i] = v[j]; v[j] = temp; } /***************************************************************************** * snort_qsort() *****************************************************************************/ void snort_qsort( struct snort_nlist * v[], int left, int right ) { int i, last; if ( left >= right ) { return; } snort_swap( v, left, (left + right) / 2 ); last = left; for ( i = left + 1; i <= right; i++ ) { if ( v[i]->ui_n > v[left]->ui_n ) { snort_swap( v, ++last, i ); } } snort_swap( v, left, last ); snort_qsort( v, left, last - 1 ); snort_qsort( v, last + 1, right ); } /***************************************************************************** * snort_hash() *****************************************************************************/ unsigned int snort_hash( char * p_char ) { unsigned int ui_hashval; for ( ui_hashval = 0; *p_char != '\0'; p_char++ ) { ui_hashval = *p_char + 31 * ui_hashval; } return( ui_hashval % HASHSIZE ); } /***************************************************************************** * snort_lookup() *****************************************************************************/ struct snort_nlist * snort_lookup( struct snort_nlist * hashtab[], char * p_char ) { struct snort_nlist * np; for ( np = hashtab[snort_hash(p_char)]; np != NULL; np = np->next ) { if ( strcmp(p_char, np->p_char) == 0 ) { return( np ); } } return( NULL ); } /***************************************************************************** * snort_install() *****************************************************************************/ struct snort_nlist * snort_install( struct snort_nlist * hashtab[], char * p_char ) { struct snort_nlist * np; unsigned int ui_hashval; if ( (np = snort_lookup(hashtab, p_char)) == NULL ) { if ( (np = (struct snort_nlist *)malloc(sizeof(struct snort_nlist))) == NULL ) { return( NULL ); } if ( (np->p_char = strdup(p_char)) == NULL ) { free( np ); return( NULL ); } ui_hashval = snort_hash( p_char ); np->next = hashtab[ ui_hashval ]; hashtab[ ui_hashval ] = np; np->ui_n = 1; np->p = NULL; } else { np->ui_n += 1; } return( np ); } /***************************************************************************** * snort_init() *****************************************************************************/ void snort_init( struct snort_nlist * hashtab[] ) { int i; for ( i = 0; i < HASHSIZE; i++ ) { hashtab[ i ] = NULL; } } /***************************************************************************** * snort_cleanup() *****************************************************************************/ void snort_cleanup( struct snort_nlist * hashtab[] ) { int i, j, k; struct snort_nlist * np_src, * np_dst, * np_msg, * np; for ( i = 0; i < HASHSIZE; i++ ) { np_src = hashtab[i]; while ( np_src != NULL ) { for ( j = 0; j < HASHSIZE; j++ ) { np_dst = ((struct snort_src *)np_src->p)->dst_hashtab[j]; while ( np_dst != NULL ) { for ( k = 0; k < HASHSIZE; k++ ) { np_msg = ((struct snort_dst *)np_dst->p)->msg_hashtab[k]; while ( np_msg != NULL ) { if ( np_msg->p_char != NULL ) { free( np_msg->p_char ); } if ( np_msg->p != NULL ) { if ( ((struct snort_msg *)np_msg->p)->pc_timestamp != NULL ) { free( ((struct snort_msg *)np_msg->p)->pc_timestamp ); } free( np_msg->p ); } np = np_msg->next; free( np_msg ); np_msg = np; } } if ( np_dst->p_char != NULL ) { free( np_dst->p_char ); } if ( np_dst->p != NULL ) { free( np_dst->p ); } np = np_dst->next; free( np_dst ); np_dst = np; } } if ( np_src->p_char != NULL ) { free( np_src->p_char ); } if ( np_src->p != NULL ) { free( np_src->p ); } np = np_src->next; free( np_src ); np_src = np; } } } /***************************************************************************** * snort_fopen() *****************************************************************************/ struct snort_file * snort_fopen( char * pc_path, char * pc_mode ) { struct snort_file * p_sf; if ( (p_sf = (struct snort_file *)malloc(sizeof(struct snort_file))) == NULL ) { return( NULL ); } if ( (p_sf->p_file = fopen(pc_path, pc_mode)) == NULL ) { free( p_sf ); return( NULL ); } p_sf->i_bufsize = 256; if ( (p_sf->pc_buffer = (char *)malloc(p_sf->i_bufsize)) == NULL ) { fclose( p_sf->p_file ); free( p_sf ); return( NULL ); } return( p_sf ); } /***************************************************************************** * snort_fgets() *****************************************************************************/ int snort_fgets( struct snort_file * p_sf ) { char * p_char; if ( fgets(p_sf->pc_buffer, p_sf->i_bufsize, p_sf->p_file) == NULL ) { return( -1 ); } while ( (p_char = strchr(p_sf->pc_buffer, '\n')) == NULL ) { p_sf->i_bufsize *= 2; if ( (p_char = (char *)realloc(p_sf->pc_buffer, p_sf->i_bufsize)) == NULL ) { return( -1 ); } fprintf( stderr, "snort_fgets(): reallocating buffer from %i bytes to %i bytes.\n", p_sf->i_bufsize / 2, p_sf->i _bufsize ); p_sf->pc_buffer = p_char; if ( fgets(p_sf->pc_buffer + strlen(p_sf->pc_buffer), p_sf->i_bufsize - strlen(p_sf->pc_buffer), p_sf->p_file) == NULL ) { return( -1 ); } } *p_char = '\0'; return( 0 ); } /***************************************************************************** * snort_fclose() *****************************************************************************/ void snort_fclose( struct snort_file * p_sf ) { free( p_sf->pc_buffer ); fclose( p_sf->p_file ); free( p_sf ); } /***************************************************************************** * snort_parse() *****************************************************************************/ int snort_parse( struct snort_file * p_sf, struct snort_nlist * src_hashtab[] ) { int b_msg = 0; char pc_src[ IPADDRSIZE + 1 ]; char pc_dst[ IPADDRSIZE + 1 ]; char * pc_msg; int i_msgsize = p_sf->i_bufsize; char * p_char; char * pc_srcchr; char * pc_dstchr; char * pc_srcport; char * pc_dstport; unsigned int ui_port; struct snort_nlist * np; if ( (pc_msg = (char *)malloc(i_msgsize)) == NULL ) { return( -1 ); } while ( snort_fgets(p_sf) == 0 ) { if ( p_sf->pc_buffer[0] == '[' ) { b_msg = 1; if ( i_msgsize != p_sf->i_bufsize ) { i_msgsize = p_sf->i_bufsize; if ( (p_char = (char *)realloc(pc_msg, i_msgsize)) == NULL ) { free( pc_msg ); return( -1 ); } pc_msg = p_char; } strcpy( pc_msg, p_sf->pc_buffer ); } else if ( b_msg == 1 ) { if ( (p_char = strstr(p_sf->pc_buffer, " -> ")) != NULL ) { *p_char = '\0'; pc_dstchr = p_char + 4; pc_dstport = NULL; if ( (p_char = strchr(pc_dstchr, ':')) != NULL ) { *p_char = '\0'; pc_dstport = p_char + 1; } strncpy( pc_dst, pc_dstchr, IPADDRSIZE ); pc_dst[ IPADDRSIZE ] = '\0'; if ( (p_char = strchr(p_sf->pc_buffer, ' ')) != NULL ) { *p_char = '\0'; pc_srcchr = p_char + 1; pc_srcport = NULL; if ( (p_char = strchr(pc_srcchr, ':')) != NULL ) { *p_char = '\0'; pc_srcport = p_char + 1; } strncpy( pc_src, pc_srcchr, IPADDRSIZE ); pc_src[ IPADDRSIZE ] = '\0'; if ( (np = snort_install(src_hashtab, pc_src)) == NULL ) { free( pc_msg ); return( -1 ); } if ( np->p == NULL ) { if ( (np->p = malloc(sizeof(struct snort_src))) == NULL ) { free( pc_msg ); return( -1 ); } snort_init( ((struct snort_src *)(np->p))->dst_hashtab ); } if ( (np = snort_install(((struct snort_src *)(np->p))->dst_hashtab, pc_dst)) == NULL ) { free( pc_msg ); return( -1 ); } if ( np->p == NULL ) { if ( (np->p = malloc(sizeof(struct snort_dst))) == NULL ) { free( pc_msg ); return( -1 ); } snort_init( ((struct snort_dst *)(np->p))->msg_hashtab ); } if ( (np = snort_install(((struct snort_dst *)(np->p))->msg_hashtab, pc_msg)) == NULL ) { free( pc_msg ); return( -1 ); } if ( np->p == NULL ) { if ( (np->p = malloc(sizeof(struct snort_msg))) == NULL ) { free( pc_msg ); return( -1 ); } ((struct snort_msg *)np->p)->pc_timestamp = strdup( p_sf->pc_buffer ); ((struct snort_msg *)np->p)->ui_srcminport = (unsigned int)(-1); ((struct snort_msg *)np->p)->ui_srcmaxport = 0; ((struct snort_msg *)np->p)->ui_dstminport = (unsigned int)(-1); ((struct snort_msg *)np->p)->ui_dstmaxport = 0; } if ( pc_srcport != NULL ) { ui_port = atoi( pc_srcport ); if ( ui_port < ((struct snort_msg *)np->p)->ui_srcminport ) { ((struct snort_msg *)np->p)->ui_srcminport = ui_port; } if ( ui_port > ((struct snort_msg *)np->p)->ui_srcmaxport ) { ((struct snort_msg *)np->p)->ui_srcmaxport = ui_port; } } if ( pc_dstport != NULL ) { ui_port = atoi( pc_dstport ); if ( ui_port < ((struct snort_msg *)np->p)->ui_dstminport ) { ((struct snort_msg *)np->p)->ui_dstminport = ui_port; } if ( ui_port > ((struct snort_msg *)np->p)->ui_dstmaxport ) { ((struct snort_msg *)np->p)->ui_dstmaxport = ui_port; } } b_msg = 0; } } } } free( pc_msg ); return( 0 ); } /***************************************************************************** * snort_qsortinit() *****************************************************************************/ struct snort_nlist ** snort_qsortinit( struct snort_nlist * hashtab[] ) { int i, j; struct snort_nlist * np; struct snort_nlist ** qsorttab; i = 0; for ( j = 0; j < HASHSIZE; j++ ) { for ( np = hashtab[j]; np != NULL; np = np->next ) { i += 1; } } if ( (qsorttab = (struct snort_nlist **)malloc((i + 1) * sizeof(struct snort_nlist *))) == NULL ) { return( NULL ); } i = 0; for ( j = 0; j < HASHSIZE; j++ ) { for ( np = hashtab[j]; np != NULL; np = np->next ) { qsorttab[ i++ ] = np; } } qsorttab[ i ] = NULL; return( qsorttab ); } /***************************************************************************** * snort_qsortcleanup() *****************************************************************************/ void snort_qsortcleanup( struct snort_nlist ** qsorttab ) { free( qsorttab ); } /***************************************************************************** * snort_result() *****************************************************************************/ void snort_result( struct snort_nlist * src_hashtab[] ) { int i, j, k; struct snort_nlist ** src_qsorttab, ** dst_qsorttab, ** msg_qsorttab; if ( (src_qsorttab = snort_qsortinit(src_hashtab)) == NULL ) { return; } for ( i = 0; src_qsorttab[i] != NULL; i++ ) { ; } snort_qsort( src_qsorttab, 0, i - 1 ); for ( i = 0; src_qsorttab[i] != NULL; i++ ) { printf( "\n* %s (%u)\n", src_qsorttab[i]->p_char, src_qsorttab[i]->ui_n ); if ( (dst_qsorttab = snort_qsortinit(((struct snort_src *)src_qsorttab[i]->p)->dst_hashtab)) == NULL ) { snort_qsortcleanup( src_qsorttab ); return; } for ( j = 0; dst_qsorttab[j] != NULL; j++ ) { ; } snort_qsort( dst_qsorttab, 0, j - 1 ); for ( j = 0; dst_qsorttab[j] != NULL; j++ ) { printf( " - %s (%u)\n", dst_qsorttab[j]->p_char, dst_qsorttab[j]->ui_n ); if ( (msg_qsorttab = snort_qsortinit(((struct snort_dst *)dst_qsorttab[j]->p)->msg_hashtab)) == NULL ) { snort_qsortcleanup( dst_qsorttab ); snort_qsortcleanup( src_qsorttab ); return; } for ( k = 0; msg_qsorttab[k] != NULL; k++ ) { ; } snort_qsort( msg_qsorttab, 0, k - 1 ); for ( k = 0; msg_qsorttab[k] != NULL; k++ ) { fprintf( stdout, " %s (%u)\n", msg_qsorttab[k]->p_char, msg_qsorttab[k]->ui_n ); fprintf( stdout, " " ); if ( ((struct snort_msg *)msg_qsorttab[k]->p)->pc_timestamp == NULL ) { fprintf( stdout, "NULL" ); } else { fprintf( stdout, "%s", ((struct snort_msg *)msg_qsorttab[k]->p)->pc_timestamp ); } if ( ((struct snort_msg *)msg_qsorttab[k]->p)->ui_srcmaxport ) { if ( ((struct snort_msg *)msg_qsorttab[k]->p)->ui_srcminport == ((struct snort_msg *)msg _qsorttab[k]->p)->ui_srcmaxport ) { fprintf( stdout, ", srcport = %u", ((struct snort_msg *)msg_qsorttab[k]->p)->ui_ srcminport ); } else { fprintf( stdout, ", srcport min/max = %u/%u", ((struct snort_msg *)msg_qsorttab[ k]->p)->ui_srcminport, ((struct snort_msg *)msg_qsorttab[k]->p)->ui_srcmaxport ); } } if ( ((struct snort_msg *)msg_qsorttab[k]->p)->ui_dstmaxport ) { if ( ((struct snort_msg *)msg_qsorttab[k]->p)->ui_dstminport == ((struct snort_msg *)msg _qsorttab[k]->p)->ui_dstmaxport ) { fprintf( stdout, ", dstport = %u", ((struct snort_msg *)msg_qsorttab[k]->p)->ui_ dstminport ); } else { fprintf( stdout, ", dstport min/max = %u/%u", ((struct snort_msg *)msg_qsorttab[ k]->p)->ui_dstminport, ((struct snort_msg *)msg_qsorttab[k]->p)->ui_dstmaxport ); } } fprintf( stdout, "\n" ); } snort_qsortcleanup( msg_qsorttab ); } snort_qsortcleanup( dst_qsorttab ); } snort_qsortcleanup( src_qsorttab ); } /***************************************************************************** * main() *****************************************************************************/ int main( int i_argc, char * ppc_argv[] ) { struct snort_file * p_sf; struct snort_nlist * src_hashtab[ HASHSIZE ]; if ( i_argc != 2 ) { return( -1 ); } if ( (p_sf = snort_fopen(ppc_argv[1], "r")) == NULL ) { return( -1 ); } snort_init( src_hashtab ); if ( snort_parse(p_sf, src_hashtab) == 0 ) { snort_result( src_hashtab ); } snort_cleanup( src_hashtab ); snort_fclose( p_sf ); return( 0 ); }