Integration with GeoIP and GMaps in web interface

This commit is contained in:
BlackLight 2010-12-01 23:25:41 +01:00
parent 9449065aa0
commit e084f75b73
13 changed files with 322 additions and 12 deletions

View File

@ -27,6 +27,7 @@ correlation.c \
db.c \
fkmeans/kmeans.c \
fsom/fsom.c \
geo.c \
modules.c \
mysql.c \
neural.c \

View File

@ -85,8 +85,8 @@ am_libsf_ai_preproc_la_OBJECTS = libsf_ai_preproc_la-alert_history.lo \
libsf_ai_preproc_la-cluster.lo \
libsf_ai_preproc_la-correlation.lo libsf_ai_preproc_la-db.lo \
libsf_ai_preproc_la-kmeans.lo libsf_ai_preproc_la-fsom.lo \
libsf_ai_preproc_la-modules.lo libsf_ai_preproc_la-mysql.lo \
libsf_ai_preproc_la-neural.lo \
libsf_ai_preproc_la-geo.lo libsf_ai_preproc_la-modules.lo \
libsf_ai_preproc_la-mysql.lo libsf_ai_preproc_la-neural.lo \
libsf_ai_preproc_la-neural_cluster.lo \
libsf_ai_preproc_la-outdb.lo libsf_ai_preproc_la-postgresql.lo \
libsf_ai_preproc_la-regex.lo libsf_ai_preproc_la-spp_ai.lo \
@ -271,6 +271,7 @@ correlation.c \
db.c \
fkmeans/kmeans.c \
fsom/fsom.c \
geo.c \
modules.c \
mysql.c \
neural.c \
@ -426,6 +427,9 @@ libsf_ai_preproc_la-kmeans.lo: fkmeans/kmeans.c
libsf_ai_preproc_la-fsom.lo: fsom/fsom.c
$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_ai_preproc_la_CFLAGS) $(CFLAGS) -c -o libsf_ai_preproc_la-fsom.lo `test -f 'fsom/fsom.c' || echo '$(srcdir)/'`fsom/fsom.c
libsf_ai_preproc_la-geo.lo: geo.c
$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_ai_preproc_la_CFLAGS) $(CFLAGS) -c -o libsf_ai_preproc_la-geo.lo `test -f 'geo.c' || echo '$(srcdir)/'`geo.c
libsf_ai_preproc_la-modules.lo: modules.c
$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsf_ai_preproc_la_CFLAGS) $(CFLAGS) -c -o libsf_ai_preproc_la-modules.lo `test -f 'modules.c' || echo '$(srcdir)/'`modules.c

5
TODO
View File

@ -4,7 +4,9 @@ AVERAGE/HIGH PRIORITY:
- Code profiling
- Comment all the code!!!
- Testing more scenarios, making more hyperalert models
- Support for more logs
- Geographical IP localization and visualization
- True bayesian temporal correlation
=============
LOW PRIORITY:
@ -35,4 +37,5 @@ DONE:
+ Manual alert correlation from the web interface
+ Neural network for alert correlation
+ Supporting extra modules for alert correlation
+ Testing more scenarios, making more hyperalert models

View File

@ -31,6 +31,7 @@
/** \defgroup alert_parser Parse the alert log into binary structures
* @{ */
PRIVATE AI_geoip_cache *geoip = NULL;
PRIVATE AI_snort_alert *alerts = NULL;
PRIVATE FILE *alert_fp = NULL;
PRIVATE pthread_mutex_t alert_mutex;
@ -124,16 +125,19 @@ AI_file_alertparser_thread ( void* arg )
int nmatches = 0;
char line[8192];
char strtime[256];
char ip[INET_ADDRSTRLEN] = { 0 };
char **matches = NULL;
double *geocoord = NULL;
time_t stamp;
struct tm *_tm;
struct logtime ltime;
struct pkt_key key;
struct pkt_info *info;
AI_snort_alert *alert = NULL;
AI_snort_alert *tmp = NULL;
BOOL in_alert = false;
AI_geoip_cache *found = NULL;
AI_snort_alert *alert = NULL;
AI_snort_alert *tmp = NULL;
BOOL in_alert = false;
pthread_t alerts_pool_thread;
@ -264,6 +268,37 @@ AI_file_alertparser_thread ( void* arg )
alert->stream = info;
}
}
/* GeoIP stuff */
memset ( ip, 0, sizeof ( ip ));
inet_ntop ( AF_INET, &(alert->ip_src_addr), ip, sizeof ( ip ));
HASH_FIND_STR ( geoip, ip, found );
if ( !found )
{
if ( !( found = (AI_geoip_cache*) malloc ( sizeof ( AI_geoip_cache ))))
{
AI_fatal_err ( "Fatal dynamic memory allocation error", __FILE__, __LINE__ );
}
geocoord = NULL;
strcpy ( found->ip, ip );
if ( AI_geoinfobyaddr ( ip, &geocoord ) > 0 )
{
found->geocoord[0] = geocoord[0];
found->geocoord[1] = geocoord[1];
} else {
found->geocoord[0] = 0.0;
found->geocoord[1] = 0.0;
}
HASH_ADD_STR ( geoip, ip, found );
free ( geocoord );
}
alert->geocoord[0] = found->geocoord[0];
alert->geocoord[1] = found->geocoord[1];
}
if ( alerts == NULL )

14
corr_rules/1-1147-10.xml Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hyperalert PUBLIC "-//blacklight//DTD HYPERALERT SNORT MODEL//EN" "http://0x00.ath.cx/hyperalert.dtd">
<hyperalert>
<snort-id>1.1147.10</snort-id>
<desc>WEB-MISC cat%20 access</desc>
<pre>HostExists(+DST_ADDR+)</pre>
<pre>HasService(+DST_ADDR+, +DST_PORT+)</pre>
<pre>HasHttpInfo(+SRC_ADDR+, +DST_ADDR+)</pre>
<post>HasFileInfo(+SRC_ADDR+, +DST_ADDR+)</post>
</hyperalert>

14
corr_rules/1-1292-9.xml Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hyperalert PUBLIC "-//blacklight//DTD HYPERALERT SNORT MODEL//EN" "http://0x00.ath.cx/hyperalert.dtd">
<hyperalert>
<snort-id>1.1292.9</snort-id>
<desc>ATTACK-RESPONSES directory listing</desc>
<pre>HostExists(+DST_ADDR+)</pre>
<pre>HasService(+DST_ADDR+, +DST_PORT+)</pre>
<pre>HasHttpInfo(+SRC_ADDR+, +DST_ADDR+)</pre>
<post>HasFileInfo(+SRC_ADDR+, +DST_ADDR+)</post>
</hyperalert>

View File

@ -2,7 +2,7 @@
<!DOCTYPE hyperalert PUBLIC "-//blacklight//DTD HYPERALERT SNORT MODEL//EN" "http://0x00.ath.cx/hyperalert.dtd">
<hyperalert>
<snort-id>1.1380.8</snort-id>
<snort-id>1.1390.8</snort-id>
<desc>Shellcode x86 inc ebx NOOP</desc>
<pre>HostExists(+DST_ADDR+)</pre>

15
corr_rules/1-15384-3.xml Normal file
View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hyperalert PUBLIC "-//blacklight//DTD HYPERALERT SNORT MODEL//EN" "http://0x00.ath.cx/hyperalert.dtd">
<hyperalert>
<snort-id>1.15384.3</snort-id>
<desc>WEB-CLIENT Apple QuickTime pict image poly structure memory corruption attempt</desc>
<pre>HostExists(+DST_ADDR+)</pre>
<pre>HasService(+DST_ADDR+, +DST_PORT+)</pre>
<pre>HasHttpInfo(+SRC_ADDR+, +DST_ADDR+)</pre>
<pre>HasFileInfo(+SRC_ADDR+, +DST_ADDR+)</pre>
<post>HasRemoteAccess(+SRC_ADDR+, +DST_ADDR+)</post>
</hyperalert>

View File

@ -190,7 +190,9 @@ __AI_correlated_alerts_to_json ()
"\t\"date\": \"%s\",\n"
"\t\"clusteredAlertsCount\": %u,\n"
"\t\"from\": \"%s:%s\",\n"
"\t\"to\": \"%s:%s\"",
"\t\"to\": \"%s:%s\",\n"
"\t\"latitude\": \"%f\",\n"
"\t\"longitude\": \"%f\"",
alert_iterator->alert_id,
alert_iterator->sid,
alert_iterator->gid,
@ -198,7 +200,9 @@ __AI_correlated_alerts_to_json ()
alert_iterator->desc,
strtime,
alert_iterator->grouped_alerts_count,
srcip, srcport, dstip, dstport
srcip, srcport, dstip, dstport,
alert_iterator->geocoord[0],
alert_iterator->geocoord[1]
);
if ( alert_iterator->stream )
@ -255,11 +259,15 @@ __AI_correlated_alerts_to_json ()
"\t\t\t\"label\": \"%s\",\n"
"\t\t\t\"date\": \"%s\",\n"
"\t\t\t\"from\": \"%s:%s\",\n"
"\t\t\t\"to\": \"%s:%s\"%s",
"\t\t\t\"to\": \"%s:%s\",\n"
"\t\t\t\"latitude\": \"%f\",\n"
"\t\t\t\"longitude\": \"%f\"%s",
alert_iterator->grouped_alerts[i]->alert_id,
alert_iterator->grouped_alerts[i]->desc,
strtime,
srcip, srcport, dstip, dstport,
alert_iterator->grouped_alerts[i]->geocoord[0],
alert_iterator->grouped_alerts[i]->geocoord[1],
(( alert_iterator->grouped_alerts[i]->stream ) ? ",\n" : "\n" )
);

38
db.c
View File

@ -30,6 +30,7 @@
PRIVATE AI_snort_alert *alerts = NULL;
PRIVATE AI_geoip_cache *geoip = NULL;
PRIVATE pthread_mutex_t mutex;
/**
@ -40,9 +41,11 @@ void*
AI_db_alertparser_thread ( void *arg )
{
unsigned int i = 0;
char ip[INET_ADDRSTRLEN] = { 0 };
char query[1024] = { 0 };
int rows = 0;
int latest_cid = 0;
double *geocoord = NULL;
time_t latest_time = time ( NULL );
pthread_t alerts_pool_thread;
@ -53,6 +56,7 @@ AI_db_alertparser_thread ( void *arg )
struct pkt_info *info = NULL;
AI_snort_alert *alert = NULL;
AI_snort_alert *tmp = NULL;
AI_geoip_cache *found = NULL;
pthread_mutex_init ( &mutex, NULL );
@ -235,6 +239,40 @@ AI_db_alertparser_thread ( void *arg )
}
}
/* Get, if available, the geographical coordinates of the attacking IP address */
if ( alert->ip_src_addr )
{
memset ( ip, 0, sizeof ( ip ));
inet_ntop ( AF_INET, &(alert->ip_src_addr), ip, sizeof ( ip ));
HASH_FIND_STR ( geoip, ip, found );
if ( !found )
{
if ( !( found = (AI_geoip_cache*) malloc ( sizeof ( AI_geoip_cache ))))
{
AI_fatal_err ( "Fatal dynamic memory allocation error", __FILE__, __LINE__ );
}
geocoord = NULL;
strcpy ( found->ip, ip );
if ( AI_geoinfobyaddr ( ip, &geocoord ) > 0 )
{
found->geocoord[0] = geocoord[0];
found->geocoord[1] = geocoord[1];
} else {
found->geocoord[0] = 0.0;
found->geocoord[1] = 0.0;
}
HASH_ADD_STR ( geoip, ip, found );
free ( geocoord );
}
alert->geocoord[0] = found->geocoord[0];
alert->geocoord[1] = found->geocoord[1];
}
DB_free_result ( res );
latest_time = time ( NULL );

144
geo.c Normal file
View File

@ -0,0 +1,144 @@
/*
* =====================================================================================
*
* Filename: geo.c
*
* Description: Get the coordinates of an IP using www.hostip.info
*
* Version: 0.1
* Created: 01/12/2010 17:18:21
* Revision: none
* Compiler: gcc
*
* Author: BlackLight (http://0x00.ath.cx), <blacklight@autistici.org>
* Licence: GNU GPL v.3
* Company: DO WHAT YOU WANT CAUSE A PIRATE IS FREE, YOU ARE A PIRATE!
*
* =====================================================================================
*/
#include "spp_ai.h"
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
/** \defgroup geoinfo Geographic info management given an IP address using geoinfo.c
* @{ */
/**
* \brief Get latitude and longitude
* \param ip IP address
* \param coord double[2] object (NULL or not) that will contain latitude and longitude
* \return 1 if the coordinates were found, -1 otherwise
*/
int
AI_geoinfobyaddr ( const char *ip, double **coord )
{
int i, sd, n_read, n_matches;
char buf[1024] = { 0 },
hostip[INET_ADDRSTRLEN] = { 0 },
query[100] = { 0 };
char **matches = NULL;
FILE *fp = NULL;
struct hostent *host = NULL;
struct sockaddr_in addr;
if ( *coord == NULL )
{
if ( !( *coord = (double*) calloc ( 2, sizeof ( double ))))
{
return -1;
}
}
if (( sd = socket ( AF_INET, SOCK_STREAM, IPPROTO_IP )) < 0 )
{
return -1;
}
if ( !( host = gethostbyname ( "www.hostip.info" )))
{
return -1;
}
inet_ntop ( AF_INET, host->h_addr_list[0], hostip, sizeof ( hostip ));
memset ( &addr, 0, sizeof ( addr ));
addr.sin_family = AF_INET;
addr.sin_port = htons ( 80 );
addr.sin_addr.s_addr = inet_addr ( hostip );
if ( connect ( sd, (struct sockaddr*) &addr, sizeof ( struct sockaddr )) < 0 )
{
return -1;
}
if ( !( fp = fdopen ( sd, "r+" )))
{
close ( sd );
return -1;
}
snprintf ( query, sizeof ( query ), "spip=%s&submit=Go", ip );
fprintf ( fp,
"POST /index.html HTTP/1.1\r\n"
"Host: www.hostip.info\r\n"
"Content-Length: %u\r\n"
"Content-Type: application/x-www-form-urlencoded; charset=utf-8\r\n"
"Connection: close\r\n\r\n"
"%s\r\n",
strlen ( query ), query
);
do
{
memset ( buf, 0, sizeof ( buf ));
n_read = fread ( buf, sizeof ( buf ), 1, fp );
if ( preg_match ( "new GLatLng.([^,]+), ([^\\)]+)", buf, &matches, &n_matches ) > 0 )
{
(*coord)[0] = strtod ( matches[0], NULL );
(*coord)[1] = strtod ( matches[1], NULL );
for ( i=0; i < n_matches; i++ )
{
free ( matches[i] );
}
free ( matches );
matches = NULL;
fclose ( fp );
close ( sd );
if ( (*coord)[0] == 0.0 && (*coord)[1] == 0.0 )
{
return -1;
} else {
return 1;
}
}
for ( i=0; i < n_matches; i++ )
{
free ( matches[i] );
}
free ( matches );
matches = NULL;
} while ( n_read > 0 );
fclose ( fp );
close ( sd );
return -1;
} /* ----- end of function AI_geoinfobyaddr ----- */
/** @} */

View File

@ -375,7 +375,17 @@ window.onload = function() {
}
content += '</td><td>' +
json_element.from + '</td><td>' + json_element.to + '</td>' +
json_element.from;
if ( parseFloat(json_element.latitude) != 0.0 ||
parseFloat(json_element.longitude) != 0.0 )
{
content += ' (<a href="http://maps.google.com/maps?geocode=&q=' +
json_element.latitude + ',' + json_element.longitude +
'" target="_blank">locate</a>)';
}
content += '</td><td>' + json_element.to + '</td>' +
'<td>' + json_element.date + '</td></tr>';
if ( json_element.clusteredAlerts )
@ -433,7 +443,18 @@ window.onload = function() {
}
content += '</td>' +
'<td>' + json_element.clusteredAlerts[j].from + '</td>' +
'<td>' + json_element.clusteredAlerts[j].from;
if ( parseFloat(json_element.clusteredAlerts[j].latitude) != 0.0 ||
parseFloat(json_element.clusteredAlerts[j].longitude) != 0.0 )
{
content += ' (<a href="http://maps.google.com/maps?geocode=&q=' +
json_element.clusteredAlerts[j].latitude + ',' +
json_element.clusteredAlerts[j].longitude +
'" target="_blank">locate</a>)';
}
content += '</td>' +
'<td>' + json_element.clusteredAlerts[j].to + '</td>' +
'<td>' + json_element.clusteredAlerts[j].date + '</td></tr>';
}

View File

@ -28,6 +28,7 @@
#include "sf_dynamic_preprocessor.h"
#include "uthash.h"
#include <netinet/in.h>
#include <pthread.h>
#define PRIVATE static
@ -420,6 +421,10 @@ typedef struct _AI_snort_alert {
* and post-conditions*/
AI_hyperalert_info *hyperalert;
/** Latitude and longitude of the attacker IP,
* if available */
double geocoord[2];
/* Parent alerts in the chain, if any */
struct _AI_snort_alert **parent_alerts;
@ -509,6 +514,13 @@ typedef struct {
UT_hash_handle hh;
} AI_alerts_per_neuron;
/*****************************************************************/
/** Hash table holding analyzed geographical IP info */
typedef struct {
char ip[INET_ADDRSTRLEN];
double geocoord[2];
UT_hash_handle hh;
} AI_geoip_cache;
/*****************************************************************/
/** Enumeration for describing the table in the output database */
@ -567,6 +579,7 @@ double AI_alert_bayesian_correlation ( const AI_snort_alert*, co
double AI_alert_neural_som_correlation ( const AI_snort_alert*, const AI_snort_alert* );
double AI_neural_correlation_weight ();
double AI_bayesian_correlation_weight ();
int AI_geoinfobyaddr ( const char*, double** );
void AI_outdb_mutex_initialize ();
void AI_store_alert_to_db ( AI_snort_alert* );