mirror of
https://github.com/BlackLight/Snort_AIPreproc.git
synced 2024-11-24 04:35:11 +01:00
Supporting manual (un)correlations from web interface
This commit is contained in:
parent
e9dd3ebfa2
commit
544daa31cc
20 changed files with 904 additions and 73 deletions
|
@ -56,7 +56,11 @@ fi
|
||||||
mkdir -p "${SHARE_PREFIX}/htdocs/js"
|
mkdir -p "${SHARE_PREFIX}/htdocs/js"
|
||||||
mkdir -p "${SHARE_PREFIX}/schemas"
|
mkdir -p "${SHARE_PREFIX}/schemas"
|
||||||
install -m 0644 "${PWD}/htdocs/index.html" "${SHARE_PREFIX}/htdocs"
|
install -m 0644 "${PWD}/htdocs/index.html" "${SHARE_PREFIX}/htdocs"
|
||||||
|
install -m 0644 "${PWD}/htdocs/manual_correlations.dtd" "${SHARE_PREFIX}/htdocs"
|
||||||
|
install -m 0644 "${PWD}/htdocs/manual_correlations.xml" "${SHARE_PREFIX}/htdocs"
|
||||||
|
install -m 0644 "${PWD}/htdocs/manual_uncorrelations.xml" "${SHARE_PREFIX}/htdocs"
|
||||||
install -m 0755 "${PWD}/htdocs/pcap.cgi" "${SHARE_PREFIX}/htdocs"
|
install -m 0755 "${PWD}/htdocs/pcap.cgi" "${SHARE_PREFIX}/htdocs"
|
||||||
|
install -m 0755 "${PWD}/htdocs/correlate.cgi" "${SHARE_PREFIX}/htdocs"
|
||||||
install -m 0644 "${PWD}/htdocs/js/Curry-1.0.1.js" "${SHARE_PREFIX}/htdocs/js"
|
install -m 0644 "${PWD}/htdocs/js/Curry-1.0.1.js" "${SHARE_PREFIX}/htdocs/js"
|
||||||
install -m 0644 "${PWD}/htdocs/js/dracula_algorithms.js" "${SHARE_PREFIX}/htdocs/js"
|
install -m 0644 "${PWD}/htdocs/js/dracula_algorithms.js" "${SHARE_PREFIX}/htdocs/js"
|
||||||
install -m 0644 "${PWD}/htdocs/js/dracula_graffle.js" "${SHARE_PREFIX}/htdocs/js"
|
install -m 0644 "${PWD}/htdocs/js/dracula_graffle.js" "${SHARE_PREFIX}/htdocs/js"
|
||||||
|
|
|
@ -832,7 +832,11 @@ fi
|
||||||
mkdir -p "${SHARE_PREFIX}/htdocs/js"
|
mkdir -p "${SHARE_PREFIX}/htdocs/js"
|
||||||
mkdir -p "${SHARE_PREFIX}/schemas"
|
mkdir -p "${SHARE_PREFIX}/schemas"
|
||||||
install -m 0644 "${PWD}/htdocs/index.html" "${SHARE_PREFIX}/htdocs"
|
install -m 0644 "${PWD}/htdocs/index.html" "${SHARE_PREFIX}/htdocs"
|
||||||
|
install -m 0644 "${PWD}/htdocs/manual_correlations.dtd" "${SHARE_PREFIX}/htdocs"
|
||||||
|
install -m 0644 "${PWD}/htdocs/manual_correlations.xml" "${SHARE_PREFIX}/htdocs"
|
||||||
|
install -m 0644 "${PWD}/htdocs/manual_uncorrelations.xml" "${SHARE_PREFIX}/htdocs"
|
||||||
install -m 0755 "${PWD}/htdocs/pcap.cgi" "${SHARE_PREFIX}/htdocs"
|
install -m 0755 "${PWD}/htdocs/pcap.cgi" "${SHARE_PREFIX}/htdocs"
|
||||||
|
install -m 0755 "${PWD}/htdocs/correlate.cgi" "${SHARE_PREFIX}/htdocs"
|
||||||
install -m 0644 "${PWD}/htdocs/js/Curry-1.0.1.js" "${SHARE_PREFIX}/htdocs/js"
|
install -m 0644 "${PWD}/htdocs/js/Curry-1.0.1.js" "${SHARE_PREFIX}/htdocs/js"
|
||||||
install -m 0644 "${PWD}/htdocs/js/dracula_algorithms.js" "${SHARE_PREFIX}/htdocs/js"
|
install -m 0644 "${PWD}/htdocs/js/dracula_algorithms.js" "${SHARE_PREFIX}/htdocs/js"
|
||||||
install -m 0644 "${PWD}/htdocs/js/dracula_graffle.js" "${SHARE_PREFIX}/htdocs/js"
|
install -m 0644 "${PWD}/htdocs/js/dracula_graffle.js" "${SHARE_PREFIX}/htdocs/js"
|
||||||
|
|
3
TODO
3
TODO
|
@ -2,13 +2,14 @@
|
||||||
AVERAGE/HIGH PRIORITY:
|
AVERAGE/HIGH PRIORITY:
|
||||||
======================
|
======================
|
||||||
|
|
||||||
|
- XML::Simple dependancy
|
||||||
|
- Manual alert correlation from the web interface
|
||||||
- Bayesian network
|
- Bayesian network
|
||||||
- Modules for correlation coefficients
|
- Modules for correlation coefficients
|
||||||
- Code profiling
|
- Code profiling
|
||||||
- Comment all the code!!!
|
- Comment all the code!!!
|
||||||
- Neural network for computing k
|
- Neural network for computing k
|
||||||
- Testing more scenarios, making more hyperalert models
|
- Testing more scenarios, making more hyperalert models
|
||||||
- Manual alert correlation from the web interface
|
|
||||||
|
|
||||||
=============
|
=============
|
||||||
LOW PRIORITY:
|
LOW PRIORITY:
|
||||||
|
|
|
@ -347,20 +347,20 @@ AI_file_alertparser_thread ( void* arg )
|
||||||
} else if ( preg_match ( "^([0-9]{2})/([0-9]{2})-([0-9]{2}):([0-9]{2}):([0-9]{2})\\.[0-9]+\\s+([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}):([0-9]{1,5})\\s*"
|
} else if ( preg_match ( "^([0-9]{2})/([0-9]{2})-([0-9]{2}):([0-9]{2}):([0-9]{2})\\.[0-9]+\\s+([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}):([0-9]{1,5})\\s*"
|
||||||
"->\\s*([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}):([0-9]{1,5})",
|
"->\\s*([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}):([0-9]{1,5})",
|
||||||
line, &matches, &nmatches ) > 0 ) {
|
line, &matches, &nmatches ) > 0 ) {
|
||||||
stamp = time(NULL);
|
stamp = time (NULL);
|
||||||
_tm = localtime ( &stamp );
|
_tm = localtime ( &stamp );
|
||||||
|
|
||||||
ltime.year = (unsigned short) _tm->tm_year + 1900;
|
ltime.year = (unsigned short) _tm->tm_year + 1900;
|
||||||
ltime.day = (unsigned short) strtoul ( matches[0], NULL, 10 );
|
ltime.day = (unsigned short) strtoul ( matches[1], NULL, 10 );
|
||||||
ltime.month = (unsigned short) strtoul ( matches[1], NULL, 10 );
|
ltime.month = (unsigned short) strtoul ( matches[0], NULL, 10 );
|
||||||
ltime.hour = (unsigned short) strtoul ( matches[2], NULL, 10 );
|
ltime.hour = (unsigned short) strtoul ( matches[2], NULL, 10 );
|
||||||
ltime.min = (unsigned short) strtoul ( matches[3], NULL, 10 );
|
ltime.min = (unsigned short) strtoul ( matches[3], NULL, 10 );
|
||||||
ltime.sec = (unsigned short) strtoul ( matches[4], NULL, 10 );
|
ltime.sec = (unsigned short) strtoul ( matches[4], NULL, 10 );
|
||||||
|
|
||||||
snprintf ( strtime, sizeof(strtime), "%02hu/%02hu/%04hu, %02hu:%02hu:%02hu",
|
snprintf ( strtime, sizeof(strtime), "%02hu/%02hu/%04hu, %02hu:%02hu:%02hu",
|
||||||
ltime.day, ltime.month, ltime.year, ltime.hour, ltime.min, ltime.sec );
|
ltime.month, ltime.day, ltime.year, ltime.hour, ltime.min, ltime.sec );
|
||||||
|
|
||||||
strptime ( strtime, "%d/%m/%Y, %H:%M:%S", _tm );
|
strptime ( strtime, "%m/%d/%Y, %H:%M:%S", _tm );
|
||||||
alert->timestamp = mktime ( _tm );
|
alert->timestamp = mktime ( _tm );
|
||||||
|
|
||||||
alert->ip_src_addr = inet_addr ( matches[5] );
|
alert->ip_src_addr = inet_addr ( matches[5] );
|
||||||
|
@ -376,20 +376,20 @@ AI_file_alertparser_thread ( void* arg )
|
||||||
} else if ( preg_match ( "^([0-9]{2})/([0-9]{2})-([0-9]{2}):([0-9]{2}):([0-9]{2})\\.[0-9]+\\s+([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})\\s*"
|
} else if ( preg_match ( "^([0-9]{2})/([0-9]{2})-([0-9]{2}):([0-9]{2}):([0-9]{2})\\.[0-9]+\\s+([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})\\s*"
|
||||||
"->\\s*([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})",
|
"->\\s*([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})",
|
||||||
line, &matches, &nmatches ) > 0 ) {
|
line, &matches, &nmatches ) > 0 ) {
|
||||||
stamp = time(NULL);
|
stamp = time (NULL);
|
||||||
_tm = localtime ( &stamp );
|
_tm = localtime ( &stamp );
|
||||||
|
|
||||||
ltime.year = (unsigned short) _tm->tm_year + 1900;
|
ltime.year = (unsigned short) _tm->tm_year + 1900;
|
||||||
ltime.day = (unsigned short) strtoul ( matches[0], NULL, 10 );
|
ltime.day = (unsigned short) strtoul ( matches[1], NULL, 10 );
|
||||||
ltime.month = (unsigned short) strtoul ( matches[1], NULL, 10 );
|
ltime.month = (unsigned short) strtoul ( matches[0], NULL, 10 );
|
||||||
ltime.hour = (unsigned short) strtoul ( matches[2], NULL, 10 );
|
ltime.hour = (unsigned short) strtoul ( matches[2], NULL, 10 );
|
||||||
ltime.min = (unsigned short) strtoul ( matches[3], NULL, 10 );
|
ltime.min = (unsigned short) strtoul ( matches[3], NULL, 10 );
|
||||||
ltime.sec = (unsigned short) strtoul ( matches[4], NULL, 10 );
|
ltime.sec = (unsigned short) strtoul ( matches[4], NULL, 10 );
|
||||||
|
|
||||||
snprintf ( strtime, sizeof(strtime), "%02hu/%02hu/%04hu, %02hu:%02hu:%02hu",
|
snprintf ( strtime, sizeof(strtime), "%02hu/%02hu/%04hu, %02hu:%02hu:%02hu",
|
||||||
ltime.day, ltime.month, ltime.year, ltime.hour, ltime.min, ltime.sec );
|
ltime.month, ltime.day, ltime.year, ltime.hour, ltime.min, ltime.sec );
|
||||||
|
|
||||||
strptime ( strtime, "%d/%m/%Y, %H:%M:%S", _tm );
|
strptime ( strtime, "%m/%d/%Y, %H:%M:%S", _tm );
|
||||||
alert->timestamp = mktime ( _tm );
|
alert->timestamp = mktime ( _tm );
|
||||||
|
|
||||||
alert->ip_src_addr = inet_addr ( matches[5] );
|
alert->ip_src_addr = inet_addr ( matches[5] );
|
||||||
|
|
|
@ -392,8 +392,7 @@ __AI_print_clustered_alerts ( AI_snort_alert *log, FILE *fp )
|
||||||
{
|
{
|
||||||
AI_snort_alert *tmp;
|
AI_snort_alert *tmp;
|
||||||
char ip[INET_ADDRSTRLEN];
|
char ip[INET_ADDRSTRLEN];
|
||||||
char timestamp[128];
|
char *timestamp;
|
||||||
struct tm *_tm;
|
|
||||||
|
|
||||||
for ( tmp = log; tmp; tmp = tmp->next )
|
for ( tmp = log; tmp; tmp = tmp->next )
|
||||||
{
|
{
|
||||||
|
@ -404,8 +403,8 @@ __AI_print_clustered_alerts ( AI_snort_alert *log, FILE *fp )
|
||||||
|
|
||||||
fprintf ( fp, "[Priority: %d]\n", tmp->priority );
|
fprintf ( fp, "[Priority: %d]\n", tmp->priority );
|
||||||
|
|
||||||
_tm = localtime ( &tmp->timestamp );
|
timestamp = ctime ( &( tmp->timestamp ));
|
||||||
strftime ( timestamp, sizeof ( timestamp ), "%a %b %d %Y, %H:%M:%S", _tm );
|
timestamp [ strlen ( timestamp ) - 1 ] = 0;
|
||||||
fprintf ( fp, "[Grouped alerts: %d] [Starting from: %s]\n", tmp->grouped_alerts_count, timestamp );
|
fprintf ( fp, "[Grouped alerts: %d] [Starting from: %s]\n", tmp->grouped_alerts_count, timestamp );
|
||||||
|
|
||||||
if ( h_root[src_addr] && tmp->h_node[src_addr] )
|
if ( h_root[src_addr] && tmp->h_node[src_addr] )
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE hyperalert PUBLIC "-//blacklighth//DTD HYPERALERT SNORT MODEL//EN" "http://0x00.ath.cx/hyperalert.dtd">
|
<!DOCTYPE hyperalert PUBLIC "-//blacklight//DTD HYPERALERT SNORT MODEL//EN" "http://0x00.ath.cx/hyperalert.dtd">
|
||||||
|
|
||||||
<hyperalert>
|
<hyperalert>
|
||||||
<snort-id>1.1394.12</snort-id>
|
<snort-id>1.1394.12</snort-id>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE hyperalert PUBLIC "-//blacklighth//DTD HYPERALERT SNORT MODEL//EN" "http://0x00.ath.cx/hyperalert.dtd">
|
<!DOCTYPE hyperalert PUBLIC "-//blacklight//DTD HYPERALERT SNORT MODEL//EN" "http://0x00.ath.cx/hyperalert.dtd">
|
||||||
|
|
||||||
<hyperalert>
|
<hyperalert>
|
||||||
<snort-id>1.1924.8</snort-id>
|
<snort-id>1.1924.8</snort-id>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE hyperalert PUBLIC "-//blacklighth//DTD HYPERALERT SNORT MODEL//EN" "http://0x00.ath.cx/hyperalert.dtd">
|
<!DOCTYPE hyperalert PUBLIC "-//blacklight//DTD HYPERALERT SNORT MODEL//EN" "http://0x00.ath.cx/hyperalert.dtd">
|
||||||
|
|
||||||
<hyperalert>
|
<hyperalert>
|
||||||
<snort-id>1.469.4</snort-id>
|
<snort-id>1.469.4</snort-id>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE hyperalert PUBLIC "-//blacklighth//DTD HYPERALERT SNORT MODEL//EN" "http://0x00.ath.cx/hyperalert.dtd">
|
<!DOCTYPE hyperalert PUBLIC "-//blacklight//DTD HYPERALERT SNORT MODEL//EN" "http://0x00.ath.cx/hyperalert.dtd">
|
||||||
|
|
||||||
<hyperalert>
|
<hyperalert>
|
||||||
<snort-id>1.579.10</snort-id>
|
<snort-id>1.579.10</snort-id>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE hyperalert PUBLIC "-//blacklighth//DTD HYPERALERT SNORT MODEL//EN" "http://0x00.ath.cx/hyperalert.dtd">
|
<!DOCTYPE hyperalert PUBLIC "-//blacklight//DTD HYPERALERT SNORT MODEL//EN" "http://0x00.ath.cx/hyperalert.dtd">
|
||||||
|
|
||||||
<hyperalert>
|
<hyperalert>
|
||||||
<snort-id>122.1.0</snort-id>
|
<snort-id>122.1.0</snort-id>
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
<!DOCTYPE hyperalert[
|
<!DOCTYPE hyperalert[
|
||||||
<!ELEMENT hyperalert (snort-id, pre, post)>
|
<!ELEMENT hyperalert (snort-id, pre, post, desc)>
|
||||||
<!ELEMENT snort-id (#PCDATA)>
|
<!ELEMENT snort-id (#PCDATA)>
|
||||||
|
<!ELEMENT desc (#PCDATA)>
|
||||||
<!ELEMENT pre (#PCDATA)>
|
<!ELEMENT pre (#PCDATA)>
|
||||||
<!ELEMENT post (#PCDATA)>
|
<!ELEMENT post (#PCDATA)>
|
||||||
]>
|
]>
|
||||||
|
|
425
correlation.c
425
correlation.c
|
@ -41,12 +41,32 @@
|
||||||
#error "libxml2 reader not enabled\n"
|
#error "libxml2 reader not enabled\n"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** Enumeration for the types of XML tags */
|
/** Enumeration for the types of hyperalert XML tags */
|
||||||
enum { inHyperAlert, inSnortIdTag, inPreTag, inPostTag, TAG_NUM };
|
enum { inHyperAlert, inSnortIdTag, inPreTag, inPostTag, HYP_TAG_NUM };
|
||||||
|
|
||||||
PRIVATE AI_hyperalert_info *hyperalerts = NULL;
|
/** Enumeration for the types of manual correlations XML tags */
|
||||||
PRIVATE AI_snort_alert *alerts = NULL;
|
enum { inCorrelation, inCorrelations, inFromTag, inToTag, MAN_TAG_NUM };
|
||||||
PRIVATE AI_alert_correlation *correlation_table = NULL;
|
|
||||||
|
typedef struct {
|
||||||
|
int from_gid;
|
||||||
|
int from_sid;
|
||||||
|
int from_rev;
|
||||||
|
int to_gid;
|
||||||
|
int to_sid;
|
||||||
|
int to_rev;
|
||||||
|
} AI_alert_type_pair_key;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
AI_alert_type_pair_key key;
|
||||||
|
enum { manuallyNone, manuallyCorrelated, manuallyNotCorrelated } corr_type;
|
||||||
|
UT_hash_handle hh;
|
||||||
|
} AI_alert_type_pair;
|
||||||
|
|
||||||
|
PRIVATE AI_hyperalert_info *hyperalerts = NULL;
|
||||||
|
PRIVATE AI_snort_alert *alerts = NULL;
|
||||||
|
PRIVATE AI_alert_correlation *correlation_table = NULL;
|
||||||
|
PRIVATE AI_alert_type_pair *manual_correlations = NULL;
|
||||||
|
PRIVATE AI_alert_type_pair *manual_uncorrelations = NULL;
|
||||||
PRIVATE pthread_mutex_t mutex;
|
PRIVATE pthread_mutex_t mutex;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -83,10 +103,8 @@ __AI_correlated_alerts_to_dot ( AI_alert_correlation *corr, FILE *fp )
|
||||||
dst_port1[10],
|
dst_port1[10],
|
||||||
src_port2[10],
|
src_port2[10],
|
||||||
dst_port2[10],
|
dst_port2[10],
|
||||||
timestamp1[40],
|
*timestamp1,
|
||||||
timestamp2[40];
|
*timestamp2;
|
||||||
|
|
||||||
struct tm *t1, *t2;
|
|
||||||
|
|
||||||
if ( !corr )
|
if ( !corr )
|
||||||
return;
|
return;
|
||||||
|
@ -97,8 +115,8 @@ __AI_correlated_alerts_to_dot ( AI_alert_correlation *corr, FILE *fp )
|
||||||
snprintf ( src_port1, sizeof ( src_port1 ), "%d", ntohs ( corr->key.a->tcp_src_port ));
|
snprintf ( src_port1, sizeof ( src_port1 ), "%d", ntohs ( corr->key.a->tcp_src_port ));
|
||||||
snprintf ( dst_port1, sizeof ( dst_port1 ), "%d", ntohs ( corr->key.a->tcp_dst_port ));
|
snprintf ( dst_port1, sizeof ( dst_port1 ), "%d", ntohs ( corr->key.a->tcp_dst_port ));
|
||||||
|
|
||||||
t1 = localtime ( &(corr->key.a->timestamp ));
|
timestamp1 = ctime ( &(corr->key.a->timestamp ) );
|
||||||
strftime ( timestamp1, sizeof ( timestamp1 ), "%a %b %d %Y, %H:%M:%S", t1 );
|
timestamp1 [ strlen ( timestamp1 ) - 1 ] = 0;
|
||||||
|
|
||||||
inet_ntop ( AF_INET, &(corr->key.b->ip_src_addr), src_addr2, INET_ADDRSTRLEN );
|
inet_ntop ( AF_INET, &(corr->key.b->ip_src_addr), src_addr2, INET_ADDRSTRLEN );
|
||||||
inet_ntop ( AF_INET, &(corr->key.b->ip_dst_addr), dst_addr2, INET_ADDRSTRLEN );
|
inet_ntop ( AF_INET, &(corr->key.b->ip_dst_addr), dst_addr2, INET_ADDRSTRLEN );
|
||||||
|
@ -106,8 +124,8 @@ __AI_correlated_alerts_to_dot ( AI_alert_correlation *corr, FILE *fp )
|
||||||
snprintf ( src_port2, sizeof ( src_port2 ), "%d", ntohs ( corr->key.b->tcp_src_port ));
|
snprintf ( src_port2, sizeof ( src_port2 ), "%d", ntohs ( corr->key.b->tcp_src_port ));
|
||||||
snprintf ( dst_port2, sizeof ( dst_port2 ), "%d", ntohs ( corr->key.b->tcp_dst_port ));
|
snprintf ( dst_port2, sizeof ( dst_port2 ), "%d", ntohs ( corr->key.b->tcp_dst_port ));
|
||||||
|
|
||||||
t2 = localtime ( &(corr->key.b->timestamp ));
|
timestamp2 = ctime ( &(corr->key.b->timestamp ) );
|
||||||
strftime ( timestamp2, sizeof ( timestamp2 ), "%a %b %d %Y, %H:%M:%S", t2 );
|
timestamp2 [ strlen ( timestamp2 ) - 1 ] = 0;
|
||||||
|
|
||||||
fprintf ( fp,
|
fprintf ( fp,
|
||||||
"\t\"[%d.%d.%d] %s\\n"
|
"\t\"[%d.%d.%d] %s\\n"
|
||||||
|
@ -178,12 +196,18 @@ __AI_correlated_alerts_to_json ()
|
||||||
|
|
||||||
fprintf ( fp, "{\n"
|
fprintf ( fp, "{\n"
|
||||||
"\t\"id\": %lu,\n"
|
"\t\"id\": %lu,\n"
|
||||||
|
"\t\"snortSID\": \"%u\",\n"
|
||||||
|
"\t\"snortGID\": \"%u\",\n"
|
||||||
|
"\t\"snortREV\": \"%u\",\n"
|
||||||
"\t\"label\": \"%s\",\n"
|
"\t\"label\": \"%s\",\n"
|
||||||
"\t\"date\": \"%s\",\n"
|
"\t\"date\": \"%s\",\n"
|
||||||
"\t\"clusteredAlertsCount\": %u,\n"
|
"\t\"clusteredAlertsCount\": %u,\n"
|
||||||
"\t\"from\": \"%s:%s\",\n"
|
"\t\"from\": \"%s:%s\",\n"
|
||||||
"\t\"to\": \"%s:%s\"",
|
"\t\"to\": \"%s:%s\"",
|
||||||
alert_iterator->alert_id,
|
alert_iterator->alert_id,
|
||||||
|
alert_iterator->sid,
|
||||||
|
alert_iterator->gid,
|
||||||
|
alert_iterator->rev,
|
||||||
alert_iterator->desc,
|
alert_iterator->desc,
|
||||||
strtime,
|
strtime,
|
||||||
alert_iterator->grouped_alerts_count,
|
alert_iterator->grouped_alerts_count,
|
||||||
|
@ -204,7 +228,7 @@ __AI_correlated_alerts_to_json ()
|
||||||
AI_fatal_err ( "Fatal dynamic memory allocation", __FILE__, __LINE__ );
|
AI_fatal_err ( "Fatal dynamic memory allocation", __FILE__, __LINE__ );
|
||||||
}
|
}
|
||||||
|
|
||||||
memset ( encoded_pkt, 0, 4*pkt_len + 1 );
|
memset ( encoded_pkt, 0, 4*pkt_len + 1 );
|
||||||
|
|
||||||
base64_encode (
|
base64_encode (
|
||||||
(const char*) pkt_iterator->pkt->pkt_data,
|
(const char*) pkt_iterator->pkt->pkt_data,
|
||||||
|
@ -617,6 +641,348 @@ __AI_kb_correlation_coefficient ( AI_snort_alert *a, AI_snort_alert *b )
|
||||||
} /* ----- end of function __AI_kb_correlation_coefficient ----- */
|
} /* ----- end of function __AI_kb_correlation_coefficient ----- */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Parse the manual specified correlations from XML file(s) and fills the hash table
|
||||||
|
*/
|
||||||
|
|
||||||
|
PRIVATE void*
|
||||||
|
__AI_manual_correlations_parsing_thread ( void *arg )
|
||||||
|
{
|
||||||
|
unsigned int i = 0;
|
||||||
|
char manual_correlations_xml[1060] = { 0 },
|
||||||
|
manual_uncorrelations_xml[1060] = { 0 };
|
||||||
|
struct stat st;
|
||||||
|
xmlTextReaderPtr xml;
|
||||||
|
const xmlChar *tagname;
|
||||||
|
AI_alert_type_pair_key key;
|
||||||
|
AI_alert_type_pair *pair = NULL,
|
||||||
|
*found = NULL;
|
||||||
|
BOOL xml_flags[MAN_TAG_NUM] = { false };
|
||||||
|
|
||||||
|
while ( 1 )
|
||||||
|
{
|
||||||
|
/* Cleanup tables */
|
||||||
|
while ( manual_correlations )
|
||||||
|
{
|
||||||
|
pair = manual_correlations;
|
||||||
|
HASH_DEL ( manual_correlations, pair );
|
||||||
|
free ( pair );
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( manual_uncorrelations )
|
||||||
|
{
|
||||||
|
pair = manual_uncorrelations;
|
||||||
|
HASH_DEL ( manual_uncorrelations, pair );
|
||||||
|
free ( pair );
|
||||||
|
}
|
||||||
|
|
||||||
|
pair = NULL;
|
||||||
|
memset ( &key, 0, sizeof ( key ));
|
||||||
|
|
||||||
|
snprintf ( manual_correlations_xml,
|
||||||
|
sizeof ( manual_correlations_xml ),
|
||||||
|
"%s/manual_correlations.xml", config->webserv_dir );
|
||||||
|
|
||||||
|
snprintf ( manual_uncorrelations_xml,
|
||||||
|
sizeof ( manual_uncorrelations_xml ),
|
||||||
|
"%s/manual_uncorrelations.xml", config->webserv_dir );
|
||||||
|
|
||||||
|
if ( stat ( manual_correlations_xml, &st ) < 0 )
|
||||||
|
{
|
||||||
|
pthread_exit ((void*) 0);
|
||||||
|
return (void*) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( stat ( manual_uncorrelations_xml, &st ) < 0 )
|
||||||
|
{
|
||||||
|
pthread_exit ((void*) 0);
|
||||||
|
return (void*) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBXML_TEST_VERSION
|
||||||
|
|
||||||
|
/* Check manual correlations */
|
||||||
|
if ( !( xml = xmlReaderForFile ( manual_correlations_xml, NULL, 0 )))
|
||||||
|
{
|
||||||
|
pthread_exit ((void*) 0);
|
||||||
|
return (void*) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( xmlTextReaderRead ( xml ))
|
||||||
|
{
|
||||||
|
if ( !( tagname = xmlTextReaderConstName ( xml )))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ( xmlTextReaderNodeType ( xml ) == XML_READER_TYPE_ELEMENT )
|
||||||
|
{
|
||||||
|
if ( !strcasecmp ((const char*) tagname, "correlations" ))
|
||||||
|
{
|
||||||
|
if ( xml_flags[inCorrelations] )
|
||||||
|
{
|
||||||
|
AI_fatal_err ( "Tag 'correlations' opened twice in manual correlations XML file", __FILE__, __LINE__ );
|
||||||
|
} else {
|
||||||
|
xml_flags[inCorrelations] = true;
|
||||||
|
}
|
||||||
|
} else if ( !strcasecmp ((const char*) tagname, "correlation" )) {
|
||||||
|
if ( xml_flags[inCorrelation] )
|
||||||
|
{
|
||||||
|
AI_fatal_err ( "Tag 'correlation' opened twice in manual correlations XML file", __FILE__, __LINE__ );
|
||||||
|
} else {
|
||||||
|
xml_flags[inCorrelation] = true;
|
||||||
|
}
|
||||||
|
} else if ( !strcasecmp ((const char*) tagname, "from" )) {
|
||||||
|
xml_flags[inFromTag] = true;
|
||||||
|
|
||||||
|
key.from_gid = (( const char* ) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "gid" )) ?
|
||||||
|
strtol (( const char* ) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "gid" ), NULL, 10 ) : 0;
|
||||||
|
key.from_sid = (( const char* ) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "sid" )) ?
|
||||||
|
strtol (( const char* ) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "sid" ), NULL, 10 ) : 0;
|
||||||
|
key.from_rev = (( const char* ) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "rev" )) ?
|
||||||
|
strtol (( const char* ) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "rev" ), NULL, 10 ) : 0;
|
||||||
|
|
||||||
|
/* If this is a new pair, allocate the memory */
|
||||||
|
if ( pair == NULL )
|
||||||
|
{
|
||||||
|
if ( !( pair = ( AI_alert_type_pair* ) malloc ( sizeof ( AI_alert_type_pair ))))
|
||||||
|
{
|
||||||
|
AI_fatal_err ( "Fatal dynamic memory allocation error", __FILE__, __LINE__ );
|
||||||
|
}
|
||||||
|
|
||||||
|
pair->corr_type = manuallyCorrelated;
|
||||||
|
} else {
|
||||||
|
/* Otherwise, add the pair to the hash, if it's not already there */
|
||||||
|
pair->key = key;
|
||||||
|
HASH_FIND ( hh, manual_correlations, &key, sizeof ( key ), found );
|
||||||
|
|
||||||
|
if ( !found )
|
||||||
|
{
|
||||||
|
HASH_ADD ( hh, manual_correlations, key, sizeof ( key ), pair );
|
||||||
|
}
|
||||||
|
|
||||||
|
pair = NULL;
|
||||||
|
memset ( &key, 0, sizeof ( key ));
|
||||||
|
}
|
||||||
|
} else if ( !strcasecmp ((const char*) tagname, "to" )) {
|
||||||
|
xml_flags[inToTag] = true;
|
||||||
|
|
||||||
|
key.to_gid = (( const char* ) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "gid" )) ?
|
||||||
|
strtol (( const char* ) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "gid" ), NULL, 10 ) : 0;
|
||||||
|
key.to_sid = (( const char* ) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "sid" )) ?
|
||||||
|
strtol (( const char* ) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "sid" ), NULL, 10 ) : 0;
|
||||||
|
key.to_rev = (( const char* ) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "rev" )) ?
|
||||||
|
strtol (( const char* ) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "rev" ), NULL, 10 ) : 0;
|
||||||
|
|
||||||
|
/* If this is a new pair, allocate the memory */
|
||||||
|
if ( pair == NULL )
|
||||||
|
{
|
||||||
|
if ( !( pair = ( AI_alert_type_pair* ) malloc ( sizeof ( AI_alert_type_pair ))))
|
||||||
|
{
|
||||||
|
AI_fatal_err ( "Fatal dynamic memory allocation error", __FILE__, __LINE__ );
|
||||||
|
}
|
||||||
|
|
||||||
|
pair->corr_type = manuallyCorrelated;
|
||||||
|
} else {
|
||||||
|
/* Otherwise, add the pair to the hash, if it's not already there */
|
||||||
|
pair->key = key;
|
||||||
|
HASH_FIND ( hh, manual_correlations, &key, sizeof ( key ), found );
|
||||||
|
|
||||||
|
if ( !found )
|
||||||
|
{
|
||||||
|
HASH_ADD ( hh, manual_correlations, key, sizeof ( key ), pair );
|
||||||
|
}
|
||||||
|
|
||||||
|
pair = NULL;
|
||||||
|
memset ( &key, 0, sizeof ( key ));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
AI_fatal_err ( "Unrecognized tag in manual correlations XML file", __FILE__, __LINE__ );
|
||||||
|
}
|
||||||
|
} else if ( xmlTextReaderNodeType ( xml ) == XML_READER_TYPE_END_ELEMENT ) {
|
||||||
|
if ( !strcasecmp ((const char*) tagname, "correlations" ))
|
||||||
|
{
|
||||||
|
if ( !xml_flags[inCorrelations] )
|
||||||
|
{
|
||||||
|
AI_fatal_err ( "Tag 'correlations' closed but never opened in manual correlations XML file", __FILE__, __LINE__ );
|
||||||
|
} else {
|
||||||
|
xml_flags[inCorrelations] = false;
|
||||||
|
}
|
||||||
|
} else if ( !strcasecmp ((const char*) tagname, "correlation" )) {
|
||||||
|
if ( !xml_flags[inCorrelation] )
|
||||||
|
{
|
||||||
|
AI_fatal_err ( "Tag 'correlation' closed but never opened in manual correlations XML file", __FILE__, __LINE__ );
|
||||||
|
} else {
|
||||||
|
xml_flags[inCorrelation] = false;
|
||||||
|
}
|
||||||
|
} else if ( !strcasecmp ((const char*) tagname, "from" )) {
|
||||||
|
if ( !xml_flags[inFromTag] )
|
||||||
|
{
|
||||||
|
AI_fatal_err ( "Tag 'from' closed but never opened in manual correlations XML file", __FILE__, __LINE__ );
|
||||||
|
} else {
|
||||||
|
xml_flags[inFromTag] = false;
|
||||||
|
}
|
||||||
|
} else if ( !strcasecmp ((const char*) tagname, "to" )) {
|
||||||
|
if ( !xml_flags[inToTag] )
|
||||||
|
{
|
||||||
|
AI_fatal_err ( "Tag 'to' closed but never opened in manual correlations XML file", __FILE__, __LINE__ );
|
||||||
|
} else {
|
||||||
|
xml_flags[inToTag] = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
AI_fatal_err ( "Unrecognized tag in manual correlations XML file", __FILE__, __LINE__ );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xmlFreeTextReader ( xml );
|
||||||
|
xmlCleanupParser();
|
||||||
|
|
||||||
|
for ( i=0; i < MAN_TAG_NUM; i++ )
|
||||||
|
{
|
||||||
|
xml_flags[i] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check manual un-correlations */
|
||||||
|
if ( !( xml = xmlReaderForFile ( manual_uncorrelations_xml, NULL, 0 )))
|
||||||
|
{
|
||||||
|
pthread_exit ((void*) 0);
|
||||||
|
return (void*) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( xmlTextReaderRead ( xml ))
|
||||||
|
{
|
||||||
|
if ( !( tagname = xmlTextReaderConstName ( xml )))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ( xmlTextReaderNodeType ( xml ) == XML_READER_TYPE_ELEMENT )
|
||||||
|
{
|
||||||
|
if ( !strcasecmp ((const char*) tagname, "correlations" ))
|
||||||
|
{
|
||||||
|
if ( xml_flags[inCorrelations] )
|
||||||
|
{
|
||||||
|
AI_fatal_err ( "Tag 'correlations' opened twice in manual correlations XML file", __FILE__, __LINE__ );
|
||||||
|
} else {
|
||||||
|
xml_flags[inCorrelations] = true;
|
||||||
|
}
|
||||||
|
} else if ( !strcasecmp ((const char*) tagname, "correlation" )) {
|
||||||
|
if ( xml_flags[inCorrelation] )
|
||||||
|
{
|
||||||
|
AI_fatal_err ( "Tag 'correlation' opened twice in manual correlations XML file", __FILE__, __LINE__ );
|
||||||
|
} else {
|
||||||
|
xml_flags[inCorrelation] = true;
|
||||||
|
}
|
||||||
|
} else if ( !strcasecmp ((const char*) tagname, "from" )) {
|
||||||
|
xml_flags[inFromTag] = true;
|
||||||
|
|
||||||
|
key.from_gid = (( const char* ) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "gid" )) ?
|
||||||
|
strtol (( const char* ) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "gid" ), NULL, 10 ) : 0;
|
||||||
|
key.from_sid = (( const char* ) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "sid" )) ?
|
||||||
|
strtol (( const char* ) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "sid" ), NULL, 10 ) : 0;
|
||||||
|
key.from_rev = (( const char* ) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "rev" )) ?
|
||||||
|
strtol (( const char* ) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "rev" ), NULL, 10 ) : 0;
|
||||||
|
|
||||||
|
/* If this is a new pair, allocate the memory */
|
||||||
|
if ( pair == NULL )
|
||||||
|
{
|
||||||
|
if ( !( pair = ( AI_alert_type_pair* ) malloc ( sizeof ( AI_alert_type_pair ))))
|
||||||
|
{
|
||||||
|
AI_fatal_err ( "Fatal dynamic memory allocation error", __FILE__, __LINE__ );
|
||||||
|
}
|
||||||
|
|
||||||
|
pair->corr_type = manuallyNotCorrelated;
|
||||||
|
} else {
|
||||||
|
/* Otherwise, add the pair to the hash, if it's not already there */
|
||||||
|
pair->key = key;
|
||||||
|
HASH_FIND ( hh, manual_uncorrelations, &key, sizeof ( key ), found );
|
||||||
|
|
||||||
|
if ( !found )
|
||||||
|
{
|
||||||
|
HASH_ADD ( hh, manual_uncorrelations, key, sizeof ( key ), pair );
|
||||||
|
}
|
||||||
|
|
||||||
|
pair = NULL;
|
||||||
|
memset ( &key, 0, sizeof ( key ));
|
||||||
|
}
|
||||||
|
} else if ( !strcasecmp ((const char*) tagname, "to" )) {
|
||||||
|
xml_flags[inToTag] = true;
|
||||||
|
|
||||||
|
key.to_gid = (( const char* ) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "gid" )) ?
|
||||||
|
strtol (( const char* ) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "gid" ), NULL, 10 ) : 0;
|
||||||
|
key.to_sid = (( const char* ) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "sid" )) ?
|
||||||
|
strtol (( const char* ) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "sid" ), NULL, 10 ) : 0;
|
||||||
|
key.to_rev = (( const char* ) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "rev" )) ?
|
||||||
|
strtol (( const char* ) xmlTextReaderGetAttribute ( xml, (const xmlChar*) "rev" ), NULL, 10 ) : 0;
|
||||||
|
|
||||||
|
/* If this is a new pair, allocate the memory */
|
||||||
|
if ( pair == NULL )
|
||||||
|
{
|
||||||
|
if ( !( pair = ( AI_alert_type_pair* ) malloc ( sizeof ( AI_alert_type_pair ))))
|
||||||
|
{
|
||||||
|
AI_fatal_err ( "Fatal dynamic memory allocation error", __FILE__, __LINE__ );
|
||||||
|
}
|
||||||
|
|
||||||
|
pair->corr_type = manuallyNotCorrelated;
|
||||||
|
} else {
|
||||||
|
/* Otherwise, add the pair to the hash, if it's not already there */
|
||||||
|
pair->key = key;
|
||||||
|
HASH_FIND ( hh, manual_uncorrelations, &key, sizeof ( key ), found );
|
||||||
|
|
||||||
|
if ( !found )
|
||||||
|
{
|
||||||
|
HASH_ADD ( hh, manual_uncorrelations, key, sizeof ( key ), pair );
|
||||||
|
}
|
||||||
|
|
||||||
|
pair = NULL;
|
||||||
|
memset ( &key, 0, sizeof ( key ));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
AI_fatal_err ( "Unrecognized tag in manual correlations XML file", __FILE__, __LINE__ );
|
||||||
|
}
|
||||||
|
} else if ( xmlTextReaderNodeType ( xml ) == XML_READER_TYPE_END_ELEMENT ) {
|
||||||
|
if ( !strcasecmp ((const char*) tagname, "correlations" ))
|
||||||
|
{
|
||||||
|
if ( !xml_flags[inCorrelations] )
|
||||||
|
{
|
||||||
|
AI_fatal_err ( "Tag 'correlations' closed but never opened in manual correlations XML file", __FILE__, __LINE__ );
|
||||||
|
} else {
|
||||||
|
xml_flags[inCorrelations] = false;
|
||||||
|
}
|
||||||
|
} else if ( !strcasecmp ((const char*) tagname, "correlation" )) {
|
||||||
|
if ( !xml_flags[inCorrelation] )
|
||||||
|
{
|
||||||
|
AI_fatal_err ( "Tag 'correlation' closed but never opened in manual correlations XML file", __FILE__, __LINE__ );
|
||||||
|
} else {
|
||||||
|
xml_flags[inCorrelation] = false;
|
||||||
|
}
|
||||||
|
} else if ( !strcasecmp ((const char*) tagname, "from" )) {
|
||||||
|
if ( !xml_flags[inFromTag] )
|
||||||
|
{
|
||||||
|
AI_fatal_err ( "Tag 'from' closed but never opened in manual correlations XML file", __FILE__, __LINE__ );
|
||||||
|
} else {
|
||||||
|
xml_flags[inFromTag] = false;
|
||||||
|
}
|
||||||
|
} else if ( !strcasecmp ((const char*) tagname, "to" )) {
|
||||||
|
if ( !xml_flags[inToTag] )
|
||||||
|
{
|
||||||
|
AI_fatal_err ( "Tag 'to' closed but never opened in manual correlations XML file", __FILE__, __LINE__ );
|
||||||
|
} else {
|
||||||
|
xml_flags[inToTag] = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
AI_fatal_err ( "Unrecognized tag in manual correlations XML file", __FILE__, __LINE__ );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xmlFreeTextReader ( xml );
|
||||||
|
xmlCleanupParser();
|
||||||
|
sleep ( config->manualCorrelationsParsingInterval );
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_exit ((void*) 0);
|
||||||
|
return (void*) 0;
|
||||||
|
} /* ----- end of function __AI_manual_correlations_parsing_thread ----- */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Substitute the macros in hyperalert pre-conditions and post-conditions with their associated values
|
* \brief Substitute the macros in hyperalert pre-conditions and post-conditions with their associated values
|
||||||
* \param alert Reference to the hyperalert to work on
|
* \param alert Reference to the hyperalert to work on
|
||||||
|
@ -719,7 +1085,7 @@ __AI_hyperalert_from_XML ( AI_hyperalert_key key )
|
||||||
{
|
{
|
||||||
char hyperalert_file[1024] = {0};
|
char hyperalert_file[1024] = {0};
|
||||||
char snort_id[1024] = {0};
|
char snort_id[1024] = {0};
|
||||||
BOOL xmlFlags[TAG_NUM] = { false };
|
BOOL xmlFlags[HYP_TAG_NUM] = { false };
|
||||||
struct stat st;
|
struct stat st;
|
||||||
xmlTextReaderPtr xml;
|
xmlTextReaderPtr xml;
|
||||||
const xmlChar *tagname, *tagvalue;
|
const xmlChar *tagname, *tagvalue;
|
||||||
|
@ -867,13 +1233,18 @@ AI_alert_correlation_thread ( void *arg )
|
||||||
AI_alert_correlation_key corr_key;
|
AI_alert_correlation_key corr_key;
|
||||||
AI_alert_correlation *corr = NULL;
|
AI_alert_correlation *corr = NULL;
|
||||||
|
|
||||||
|
AI_alert_type_pair_key pair_key;
|
||||||
|
AI_alert_type_pair *pair = NULL,
|
||||||
|
*unpair = NULL;
|
||||||
|
|
||||||
AI_hyperalert_key key;
|
AI_hyperalert_key key;
|
||||||
AI_hyperalert_info *hyp = NULL;
|
AI_hyperalert_info *hyp = NULL;
|
||||||
|
|
||||||
AI_snort_alert *alert_iterator = NULL,
|
AI_snort_alert *alert_iterator = NULL,
|
||||||
*alert_iterator2 = NULL;
|
*alert_iterator2 = NULL;
|
||||||
|
|
||||||
pthread_t db_thread;
|
pthread_t db_thread,
|
||||||
|
manual_corr_thread;
|
||||||
|
|
||||||
#ifdef HAVE_LIBGVC
|
#ifdef HAVE_LIBGVC
|
||||||
char corr_png_file[4096] = { 0 };
|
char corr_png_file[4096] = { 0 };
|
||||||
|
@ -883,6 +1254,12 @@ AI_alert_correlation_thread ( void *arg )
|
||||||
|
|
||||||
pthread_mutex_init ( &mutex, NULL );
|
pthread_mutex_init ( &mutex, NULL );
|
||||||
|
|
||||||
|
/* Start the thread for parsing manual correlations from XML */
|
||||||
|
if ( pthread_create ( &manual_corr_thread, NULL, __AI_manual_correlations_parsing_thread, NULL ) != 0 )
|
||||||
|
{
|
||||||
|
AI_fatal_err ( "Failed to create the manual correlations parsing thread", __FILE__, __LINE__ );
|
||||||
|
}
|
||||||
|
|
||||||
while ( 1 )
|
while ( 1 )
|
||||||
{
|
{
|
||||||
sleep ( config->correlationGraphInterval );
|
sleep ( config->correlationGraphInterval );
|
||||||
|
@ -955,6 +1332,7 @@ AI_alert_correlation_thread ( void *arg )
|
||||||
__AI_correlation_table_cleanup();
|
__AI_correlation_table_cleanup();
|
||||||
correlation_table = NULL;
|
correlation_table = NULL;
|
||||||
|
|
||||||
|
/* Fill the table of correlated alerts */
|
||||||
for ( alert_iterator = alerts; alert_iterator; alert_iterator = alert_iterator->next )
|
for ( alert_iterator = alerts; alert_iterator; alert_iterator = alert_iterator->next )
|
||||||
{
|
{
|
||||||
for ( alert_iterator2 = alerts; alert_iterator2; alert_iterator2 = alert_iterator2->next )
|
for ( alert_iterator2 = alerts; alert_iterator2; alert_iterator2 = alert_iterator2->next )
|
||||||
|
@ -1026,12 +1404,23 @@ AI_alert_correlation_thread ( void *arg )
|
||||||
/* Find correlated alerts */
|
/* Find correlated alerts */
|
||||||
for ( corr = correlation_table; corr; corr = ( AI_alert_correlation* ) corr->hh.next )
|
for ( corr = correlation_table; corr; corr = ( AI_alert_correlation* ) corr->hh.next )
|
||||||
{
|
{
|
||||||
if ( corr->correlation >= corr_threshold &&
|
pair_key.from_sid = corr->key.a->sid;
|
||||||
|
pair_key.from_gid = corr->key.a->gid;
|
||||||
|
pair_key.from_rev = corr->key.a->rev;
|
||||||
|
pair_key.to_sid = corr->key.b->sid;
|
||||||
|
pair_key.to_gid = corr->key.b->gid;
|
||||||
|
pair_key.to_rev = corr->key.b->rev;
|
||||||
|
|
||||||
|
HASH_FIND ( hh, manual_correlations, &pair_key, sizeof ( pair_key ), pair );
|
||||||
|
HASH_FIND ( hh, manual_uncorrelations, &pair_key, sizeof ( pair_key ), unpair );
|
||||||
|
|
||||||
|
if ( !unpair && ( pair || (
|
||||||
|
corr->correlation >= corr_threshold &&
|
||||||
corr_threshold != 0.0 &&
|
corr_threshold != 0.0 &&
|
||||||
corr->key.a->timestamp <= corr->key.b->timestamp && ! (
|
corr->key.a->timestamp <= corr->key.b->timestamp && ! (
|
||||||
corr->key.a->gid == corr->key.b->gid &&
|
corr->key.a->gid == corr->key.b->gid &&
|
||||||
corr->key.a->sid == corr->key.b->sid &&
|
corr->key.a->sid == corr->key.b->sid &&
|
||||||
corr->key.a->rev == corr->key.b->rev ))
|
corr->key.a->rev == corr->key.b->rev ))))
|
||||||
{
|
{
|
||||||
if ( !( corr->key.a->derived_alerts = ( AI_snort_alert** ) realloc ( corr->key.a->derived_alerts, (++corr->key.a->n_derived_alerts) * sizeof ( AI_snort_alert* ))))
|
if ( !( corr->key.a->derived_alerts = ( AI_snort_alert** ) realloc ( corr->key.a->derived_alerts, (++corr->key.a->n_derived_alerts) * sizeof ( AI_snort_alert* ))))
|
||||||
AI_fatal_err ( "Fatal dynamic memory allocation error", __FILE__, __LINE__ );
|
AI_fatal_err ( "Fatal dynamic memory allocation error", __FILE__, __LINE__ );
|
||||||
|
|
178
htdocs/correlate.cgi
Executable file
178
htdocs/correlate.cgi
Executable file
|
@ -0,0 +1,178 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use XML::Simple;
|
||||||
|
use Data::Dumper;
|
||||||
|
use Env qw(QUERY_STRING DOCUMENT_ROOT);
|
||||||
|
|
||||||
|
exit 1 if ( !$QUERY_STRING );
|
||||||
|
|
||||||
|
$QUERY_STRING =~ /action=([a-z]+)/;
|
||||||
|
my $action = $1;
|
||||||
|
|
||||||
|
$QUERY_STRING =~ /from_sid=([0-9]+)/;
|
||||||
|
my $from_sid = $1;
|
||||||
|
|
||||||
|
$QUERY_STRING =~ /from_gid=([0-9]+)/;
|
||||||
|
my $from_gid = $1;
|
||||||
|
|
||||||
|
$QUERY_STRING =~ /from_rev=([0-9]+)/;
|
||||||
|
my $from_rev = $1;
|
||||||
|
|
||||||
|
$QUERY_STRING =~ /to_sid=([0-9]+)/;
|
||||||
|
my $to_sid = $1;
|
||||||
|
|
||||||
|
$QUERY_STRING =~ /to_gid=([0-9]+)/;
|
||||||
|
my $to_gid = $1;
|
||||||
|
|
||||||
|
$QUERY_STRING =~ /to_rev=([0-9]+)/;
|
||||||
|
my $to_rev = $1;
|
||||||
|
|
||||||
|
exit 1 unless (
|
||||||
|
defined ( $action ) &&
|
||||||
|
defined ( $from_sid ) &&
|
||||||
|
defined ( $from_gid ) &&
|
||||||
|
defined ( $from_rev ) &&
|
||||||
|
defined ( $to_sid ) &&
|
||||||
|
defined ( $to_gid ) &&
|
||||||
|
defined ( $to_rev ));
|
||||||
|
|
||||||
|
my $xml = new XML::Simple ( forcearray => 1 );
|
||||||
|
my $corr_data = $xml->XMLin ( "$DOCUMENT_ROOT/manual_correlations.xml" );
|
||||||
|
my $uncorr_data = $xml->XMLin ( "$DOCUMENT_ROOT/manual_uncorrelations.xml" );
|
||||||
|
|
||||||
|
if ( $action eq 'add' )
|
||||||
|
{
|
||||||
|
# Check if 'correlation' already contains this item
|
||||||
|
for my $node ( @{$corr_data->{'correlation'}} )
|
||||||
|
{
|
||||||
|
my $from = @{$node->{'from'}}[0];
|
||||||
|
my $to = @{$node->{'to'}}[0];
|
||||||
|
|
||||||
|
exit 1 if (
|
||||||
|
$from->{'sid'} eq $from_sid &&
|
||||||
|
$from->{'gid'} eq $from_gid &&
|
||||||
|
$from->{'rev'} eq $from_rev &&
|
||||||
|
$to->{'sid'} eq $to_sid &&
|
||||||
|
$to->{'gid'} eq $to_gid &&
|
||||||
|
$to->{'rev'} eq $to_rev
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
# If this node is in 'uncorrelated' alerts, remove it from there
|
||||||
|
if ( UNIVERSAL::isa ( $uncorr_data->{'correlation'}, "ARRAY" ))
|
||||||
|
{
|
||||||
|
for my $i ( 0..@{$uncorr_data->{'correlation'}}-1 )
|
||||||
|
{
|
||||||
|
if ( defined ( @{$uncorr_data->{'correlation'}}[$i] ))
|
||||||
|
{
|
||||||
|
my $from = @{@{$uncorr_data->{'correlation'}}[$i]->{'from'}}[0];
|
||||||
|
my $to = @{@{$uncorr_data->{'correlation'}}[$i]->{'to'}}[0];
|
||||||
|
|
||||||
|
splice ( @{$uncorr_data->{'correlation'}}, $i, 1 ) if (
|
||||||
|
$from->{'sid'} eq $from_sid &&
|
||||||
|
$from->{'gid'} eq $from_gid &&
|
||||||
|
$from->{'rev'} eq $from_rev &&
|
||||||
|
$to->{'sid'} eq $to_sid &&
|
||||||
|
$to->{'gid'} eq $to_gid &&
|
||||||
|
$to->{'rev'} eq $to_rev
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my %hash = (
|
||||||
|
'to' => [
|
||||||
|
{
|
||||||
|
'sid' => $to_sid,
|
||||||
|
'gid' => $to_gid,
|
||||||
|
'rev' => $to_rev,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'from' => [
|
||||||
|
{
|
||||||
|
'sid' => $from_sid,
|
||||||
|
'gid' => $from_gid,
|
||||||
|
'rev' => $from_rev
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
push @{$corr_data->{'correlation'}}, \%hash;
|
||||||
|
} elsif ( $action eq 'remove' ) {
|
||||||
|
# Check if 'un-correlation' already contains this item
|
||||||
|
for my $node ( @{$uncorr_data->{'correlation'}} )
|
||||||
|
{
|
||||||
|
my $from = @{$node->{'from'}}[0];
|
||||||
|
my $to = @{$node->{'to'}}[0];
|
||||||
|
|
||||||
|
exit 1 if (
|
||||||
|
$from->{'sid'} eq $from_sid &&
|
||||||
|
$from->{'gid'} eq $from_gid &&
|
||||||
|
$from->{'rev'} eq $from_rev &&
|
||||||
|
$to->{'sid'} eq $to_sid &&
|
||||||
|
$to->{'gid'} eq $to_gid &&
|
||||||
|
$to->{'rev'} eq $to_rev
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
# If this node is in 'correlated' alerts, remove it from there
|
||||||
|
if ( UNIVERSAL::isa ( $corr_data->{'correlation'}, "ARRAY" ))
|
||||||
|
{
|
||||||
|
for my $i ( 0..@{$corr_data->{'correlation'}}-1 )
|
||||||
|
{
|
||||||
|
if ( defined ( @{$corr_data->{'correlation'}}[$i] ))
|
||||||
|
{
|
||||||
|
my $from = @{@{$corr_data->{'correlation'}}[$i]->{'from'}}[0];
|
||||||
|
my $to = @{@{$corr_data->{'correlation'}}[$i]->{'to'}}[0];
|
||||||
|
|
||||||
|
splice ( @{$corr_data->{'correlation'}}, $i, 1 ) if (
|
||||||
|
$from->{'sid'} eq $from_sid &&
|
||||||
|
$from->{'gid'} eq $from_gid &&
|
||||||
|
$from->{'rev'} eq $from_rev &&
|
||||||
|
$to->{'sid'} eq $to_sid &&
|
||||||
|
$to->{'gid'} eq $to_gid &&
|
||||||
|
$to->{'rev'} eq $to_rev
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my %hash = (
|
||||||
|
'to' => [
|
||||||
|
{
|
||||||
|
'sid' => $to_sid,
|
||||||
|
'gid' => $to_gid,
|
||||||
|
'rev' => $to_rev
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'from' => [
|
||||||
|
{
|
||||||
|
'sid' => $from_sid,
|
||||||
|
'gid' => $from_gid,
|
||||||
|
'rev' => $from_rev
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
push @{$uncorr_data->{'correlation'}}, \%hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $xml_corr_out = $xml->XMLout ( $corr_data, RootName => "correlations" );
|
||||||
|
my $xml_uncorr_out = $xml->XMLout ( $uncorr_data, RootName => "correlations" );
|
||||||
|
|
||||||
|
open OUT, "> $DOCUMENT_ROOT/manual_correlations.xml" or exit 1;
|
||||||
|
print OUT "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||||
|
print OUT "<!DOCTYPE hyperalert PUBLIC \"-//blacklight//DTD MANUAL CORRELATIONS//EN\" \"http://0x00.ath.cx/manual_correlations.dtd\">\n\n";
|
||||||
|
print OUT $xml_corr_out."\n";
|
||||||
|
close OUT;
|
||||||
|
|
||||||
|
open OUT, "> $DOCUMENT_ROOT/manual_uncorrelations.xml" or exit 1;
|
||||||
|
print OUT "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||||
|
print OUT "<!DOCTYPE hyperalert PUBLIC \"-//blacklight//DTD MANUAL CORRELATIONS//EN\" \"http://0x00.ath.cx/manual_correlations.dtd\">\n\n";
|
||||||
|
print OUT $xml_uncorr_out."\n";
|
||||||
|
close OUT;
|
||||||
|
|
||||||
|
print "Content-Type: text/html\n\n";
|
||||||
|
|
|
@ -1,19 +1,10 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<style rel="stylesheet" type="text/css">
|
<style rel="stylesheet" type="text/css">
|
||||||
#popupAlert {
|
|
||||||
z-index : 100;
|
|
||||||
display : none;
|
|
||||||
position : absolute;
|
|
||||||
border : 1px solid #000;
|
|
||||||
background-color : #89ffa7;
|
|
||||||
color : #000;
|
|
||||||
opacity : 0.6;
|
|
||||||
padding : 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#alertInfo {
|
#alertInfo {
|
||||||
display : none;
|
display : none;
|
||||||
|
font : Fixed;
|
||||||
|
font-size : 12px;
|
||||||
border : 1px solid #888;
|
border : 1px solid #888;
|
||||||
padding : 3px;
|
padding : 3px;
|
||||||
height : 150px;
|
height : 150px;
|
||||||
|
@ -26,7 +17,18 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color : #22dd22;
|
color : #2d2;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background-color : #ddd;
|
||||||
|
color : #222;
|
||||||
|
font-size : 13px;
|
||||||
|
border : 1px dotted #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background-color : #7fc;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
@ -37,12 +39,66 @@
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
redraw = null;
|
redraw = null;
|
||||||
width = 0;
|
width = 0;
|
||||||
height = 0;
|
height = 0;
|
||||||
layouter = null;
|
layouter = null;
|
||||||
renderer = null;
|
renderer = null;
|
||||||
json = [];
|
json = [];
|
||||||
|
|
||||||
|
inCorrelateFrom = false;
|
||||||
|
inCorrelateTo = false;
|
||||||
|
correlationFrom = -1;
|
||||||
|
correlationTo = -1;
|
||||||
|
correlationFromIndex = -1;
|
||||||
|
correlationToIndex = -1;
|
||||||
|
|
||||||
|
inUncorrelateFrom = false;
|
||||||
|
inUncorrelateTo = false;
|
||||||
|
uncorrelationFrom = -1;
|
||||||
|
uncorrelationTo = -1;
|
||||||
|
uncorrelationFromIndex = -1;
|
||||||
|
uncorrelationToIndex = -1;
|
||||||
|
|
||||||
|
function correlate() {
|
||||||
|
var div = document.getElementById ( 'alertInfo' );
|
||||||
|
var button = document.getElementById ( 'correlate' );
|
||||||
|
|
||||||
|
if ( inCorrelateFrom || inCorrelateTo )
|
||||||
|
{
|
||||||
|
inCorrelateFrom = false;
|
||||||
|
div.style.backgroundColor = '#FFF';
|
||||||
|
div.style.display = 'none';
|
||||||
|
button.innerHTML = 'Manually correlate';
|
||||||
|
} else {
|
||||||
|
inCorrelateFrom = true;
|
||||||
|
inCorrelateTo = false;
|
||||||
|
div.innerHTML = '<b>Click on the source alert of the correlation</b>';
|
||||||
|
div.style.backgroundColor = '#FF9';
|
||||||
|
div.style.display = 'block';
|
||||||
|
button.innerHTML = 'Cancel manual correlation';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function uncorrelate() {
|
||||||
|
var div = document.getElementById ( 'alertInfo' );
|
||||||
|
var button = document.getElementById ( 'uncorrelate' );
|
||||||
|
|
||||||
|
if ( inUncorrelateFrom || inUncorrelateTo )
|
||||||
|
{
|
||||||
|
inUncorrelateFrom = false;
|
||||||
|
div.style.backgroundColor = '#FFF';
|
||||||
|
div.style.display = 'none';
|
||||||
|
button.innerHTML = 'Remove correlation';
|
||||||
|
} else {
|
||||||
|
inUncorrelateFrom = true;
|
||||||
|
inUncorrelateTo = false;
|
||||||
|
div.innerHTML = '<b>Click on the source alert of the un-correlation</b>';
|
||||||
|
div.style.backgroundColor = '#FF9';
|
||||||
|
div.style.display = 'block';
|
||||||
|
button.innerHTML = 'Cancel un-correlation';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
var req = new XMLHttpRequest();
|
var req = new XMLHttpRequest();
|
||||||
|
|
||||||
|
@ -116,17 +172,150 @@ window.onload = function() {
|
||||||
{
|
{
|
||||||
var id = this.id.replace ( /^alert/, "" );
|
var id = this.id.replace ( /^alert/, "" );
|
||||||
var json_element = null;
|
var json_element = null;
|
||||||
|
var index = -1;
|
||||||
|
|
||||||
for ( var i=0; i < json.length; i++ )
|
for ( var i=0; i < json.length; i++ )
|
||||||
{
|
{
|
||||||
if ( json[i].id == id )
|
if ( json[i].id == id )
|
||||||
{
|
{
|
||||||
json_element = json[i];
|
json_element = json[i];
|
||||||
|
index = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
div.style.display = 'block';
|
// Correlation stuff
|
||||||
|
if ( inCorrelateFrom )
|
||||||
|
{
|
||||||
|
inCorrelateFrom = false;
|
||||||
|
inCorrelateTo = true;
|
||||||
|
correlationFrom = id;
|
||||||
|
correlationFromIndex = index;
|
||||||
|
div.innerHTML = "<b>Click on the destination alert of the correlation</b><br>\n" +
|
||||||
|
"From: <b>" + json_element.label + "</b>";
|
||||||
|
return;
|
||||||
|
} else if ( inCorrelateTo ) {
|
||||||
|
inCorrelateTo = false;
|
||||||
|
correlationTo = id;
|
||||||
|
correlationToIndex = index;
|
||||||
|
|
||||||
|
div.style.backgroundColor = '#FFF';
|
||||||
|
div.style.display = 'none';
|
||||||
|
|
||||||
|
// Check if this correlation is already there
|
||||||
|
for ( var j=0; j < connections.length; j++ )
|
||||||
|
{
|
||||||
|
if ( connections[j].from == correlationFrom &&
|
||||||
|
connections[j].to == correlationTo )
|
||||||
|
{
|
||||||
|
document.getElementById ( 'correlate' ).innerHTML = "Manually correlate";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var from_sid = json[correlationFromIndex].snortSID;
|
||||||
|
var from_gid = json[correlationFromIndex].snortGID;
|
||||||
|
var from_rev = json[correlationFromIndex].snortREV;
|
||||||
|
var to_sid = json[correlationToIndex].snortSID;
|
||||||
|
var to_gid = json[correlationToIndex].snortGID;
|
||||||
|
var to_rev = json[correlationToIndex].snortREV;
|
||||||
|
|
||||||
|
var corr_req = new XMLHttpRequest();
|
||||||
|
corr_req.open ( 'GET', 'http://' + window.location.host +
|
||||||
|
'/correlate.cgi?' +
|
||||||
|
'action=add' +
|
||||||
|
'&from_sid=' + from_sid +
|
||||||
|
'&from_gid=' + from_gid +
|
||||||
|
'&from_rev=' + from_rev +
|
||||||
|
'&to_sid=' + to_sid +
|
||||||
|
'&to_gid=' + to_gid +
|
||||||
|
'&to_rev=' + to_rev, true );
|
||||||
|
|
||||||
|
corr_req.send ( null );
|
||||||
|
document.getElementById ( 'correlate' ).innerHTML = "Manually correlate";
|
||||||
|
|
||||||
|
connections.push ({
|
||||||
|
"from": correlationFrom,
|
||||||
|
"to" : correlationTo
|
||||||
|
});
|
||||||
|
|
||||||
|
g.addEdge ( correlationFrom, correlationTo, { directed: true });
|
||||||
|
redraw();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Un-correlation stuff
|
||||||
|
if ( inUncorrelateFrom )
|
||||||
|
{
|
||||||
|
inUncorrelateFrom = false;
|
||||||
|
inUncorrelateTo = true;
|
||||||
|
uncorrelationFrom = id;
|
||||||
|
uncorrelationFromIndex = index;
|
||||||
|
div.innerHTML = "<b>Click on the destination alert of the un-correlation</b><br>\n" +
|
||||||
|
"From: <b>" + json_element.label + "</b>";
|
||||||
|
return;
|
||||||
|
} else if ( inUncorrelateTo ) {
|
||||||
|
inUncorrelateTo = false;
|
||||||
|
uncorrelationTo = id;
|
||||||
|
uncorrelationToIndex = index;
|
||||||
|
|
||||||
|
div.style.backgroundColor = '#FFF';
|
||||||
|
div.style.display = 'none';
|
||||||
|
|
||||||
|
// Check if the alerts are already un-correlated
|
||||||
|
var correlated = false;
|
||||||
|
|
||||||
|
for ( var j=0; j < connections.length && !correlated; j++ )
|
||||||
|
{
|
||||||
|
if ( connections[j].from == uncorrelationFrom &&
|
||||||
|
connections[j].to == uncorrelationTo )
|
||||||
|
{
|
||||||
|
correlated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !correlated )
|
||||||
|
{
|
||||||
|
document.getElementById ( 'uncorrelate' ).innerHTML = "Remove correlation";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var from_sid = json[uncorrelationFromIndex].snortSID;
|
||||||
|
var from_gid = json[uncorrelationFromIndex].snortGID;
|
||||||
|
var from_rev = json[uncorrelationFromIndex].snortREV;
|
||||||
|
var to_sid = json[uncorrelationToIndex].snortSID;
|
||||||
|
var to_gid = json[uncorrelationToIndex].snortGID;
|
||||||
|
var to_rev = json[uncorrelationToIndex].snortREV;
|
||||||
|
|
||||||
|
var corr_req = new XMLHttpRequest();
|
||||||
|
corr_req.open ( 'GET', 'http://' + window.location.host +
|
||||||
|
'/correlate.cgi?' +
|
||||||
|
'action=remove' +
|
||||||
|
'&from_sid=' + from_sid +
|
||||||
|
'&from_gid=' + from_gid +
|
||||||
|
'&from_rev=' + from_rev +
|
||||||
|
'&to_sid=' + to_sid +
|
||||||
|
'&to_gid=' + to_gid +
|
||||||
|
'&to_rev=' + to_rev, true );
|
||||||
|
|
||||||
|
corr_req.send ( null );
|
||||||
|
document.getElementById ( 'uncorrelate' ).innerHTML = "Remove correlation";
|
||||||
|
|
||||||
|
// Remove the connection from the array
|
||||||
|
for ( var j=0; j < connections.length; j++ )
|
||||||
|
{
|
||||||
|
if ( connections[j].from == uncorrelationFrom &&
|
||||||
|
connections[j].to == uncorrelationTo )
|
||||||
|
{
|
||||||
|
connections.slice ( j, 1 );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
redraw();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var content =
|
var content =
|
||||||
'<table id="alertInfoTable" cellspacing="5"><tr style="background-color:#99ff99">' +
|
'<table id="alertInfoTable" cellspacing="5"><tr style="background-color:#99ff99">' +
|
||||||
'<td><b>Type</b></td><td><b>From</b></td>' +
|
'<td><b>Type</b></td><td><b>From</b></td>' +
|
||||||
|
@ -143,7 +332,9 @@ window.onload = function() {
|
||||||
json_element.packets[j].match ( /^.*(=*)$/ );
|
json_element.packets[j].match ( /^.*(=*)$/ );
|
||||||
var pad = RegExp.$1;
|
var pad = RegExp.$1;
|
||||||
var len = parseInt ( json_element.packets[j].length * 3 / 4 ) - pad.length;
|
var len = parseInt ( json_element.packets[j].length * 3 / 4 ) - pad.length;
|
||||||
|
|
||||||
json_element.date.match ( /[a-zA-Z]+\s+([a-zA-Z]+)\s+([0-9]+)\s+([0-9]+):([0-9]+):([0-9]+)\s+([0-9]+)/ );
|
json_element.date.match ( /[a-zA-Z]+\s+([a-zA-Z]+)\s+([0-9]+)\s+([0-9]+):([0-9]+):([0-9]+)\s+([0-9]+)/ );
|
||||||
|
|
||||||
var month = RegExp.$1;
|
var month = RegExp.$1;
|
||||||
var day = RegExp.$2;
|
var day = RegExp.$2;
|
||||||
var hour = RegExp.$3;
|
var hour = RegExp.$3;
|
||||||
|
@ -245,6 +436,7 @@ window.onload = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
content += '</table>';
|
content += '</table>';
|
||||||
|
div.style.display = 'block';
|
||||||
div.innerHTML = content;
|
div.innerHTML = content;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -261,7 +453,10 @@ window.onload = function() {
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="canvas" style="border: 1px solid #000"></div>
|
<div id="canvas" style="border: 1px solid #000"></div>
|
||||||
<button id="redraw" onclick="redraw();">Redraw</button>
|
<div style="height : 5px"></div>
|
||||||
|
<button id="redraw" onClick="redraw();">Redraw</button>
|
||||||
|
<button id="correlate" onClick="correlate();">Manually correlate</button>
|
||||||
|
<button id="uncorrelate" onClick="uncorrelate();">Remove correlation</button>
|
||||||
<div id="popupAlert"></div>
|
<div id="popupAlert"></div>
|
||||||
<div id="alertInfo"></div>
|
<div id="alertInfo"></div>
|
||||||
|
|
||||||
|
|
19
htdocs/manual_correlations.dtd
Normal file
19
htdocs/manual_correlations.dtd
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<!DOCTYPE correlations[
|
||||||
|
<!ELEMENT correlations (correlation)*>
|
||||||
|
<!ELEMENT correlation (from, to)>
|
||||||
|
|
||||||
|
<!ATTLIST from
|
||||||
|
sid CDATA #REQUIRED
|
||||||
|
gid CDATA #REQUIRED
|
||||||
|
rev CDATA #REQUIRED
|
||||||
|
>
|
||||||
|
|
||||||
|
<!ATTLIST to
|
||||||
|
sid CDATA #REQUIRED
|
||||||
|
gid CDATA #REQUIRED
|
||||||
|
rev CDATA #REQUIRED
|
||||||
|
>
|
||||||
|
]>
|
||||||
|
|
6
htdocs/manual_correlations.xml
Normal file
6
htdocs/manual_correlations.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE hyperalert PUBLIC "-//blacklight//DTD MANUAL CORRELATIONS//EN" "http://0x00.ath.cx/manual_correlations.dtd">
|
||||||
|
|
||||||
|
<correlations>
|
||||||
|
</correlations>
|
||||||
|
|
6
htdocs/manual_uncorrelations.xml
Normal file
6
htdocs/manual_uncorrelations.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE hyperalert PUBLIC "-//blacklight//DTD MANUAL CORRELATIONS//EN" "http://0x00.ath.cx/manual_correlations.dtd">
|
||||||
|
|
||||||
|
<correlations>
|
||||||
|
</correlations>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/perl
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
58
spp_ai.c
58
spp_ai.c
|
@ -186,24 +186,25 @@ static AI_config * AI_parse(char *args)
|
||||||
hierarchy_node **hierarchy_nodes = NULL;
|
hierarchy_node **hierarchy_nodes = NULL;
|
||||||
int n_hierarchy_nodes = 0;
|
int n_hierarchy_nodes = 0;
|
||||||
|
|
||||||
unsigned short webserv_port = 0;
|
unsigned short webserv_port = 0;
|
||||||
unsigned long cleanup_interval = 0,
|
unsigned long cleanup_interval = 0,
|
||||||
stream_expire_interval = 0,
|
stream_expire_interval = 0,
|
||||||
alertfile_len = 0,
|
alertfile_len = 0,
|
||||||
alert_history_file_len = 0,
|
alert_history_file_len = 0,
|
||||||
alert_serialization_interval = 0,
|
alert_serialization_interval = 0,
|
||||||
alert_bufsize = 0,
|
alert_bufsize = 0,
|
||||||
bayesian_correlation_interval = 0,
|
bayesian_correlation_interval = 0,
|
||||||
bayesian_correlation_cache_validity = 0,
|
bayesian_correlation_cache_validity = 0,
|
||||||
clusterfile_len = 0,
|
clusterfile_len = 0,
|
||||||
cluster_max_alert_interval = 0,
|
cluster_max_alert_interval = 0,
|
||||||
corr_rules_dir_len = 0,
|
corr_rules_dir_len = 0,
|
||||||
corr_alerts_dir_len = 0,
|
corr_alerts_dir_len = 0,
|
||||||
webserv_dir_len = 0,
|
webserv_dir_len = 0,
|
||||||
webserv_banner_len = 0,
|
webserv_banner_len = 0,
|
||||||
alert_clustering_interval = 0,
|
alert_clustering_interval = 0,
|
||||||
database_parsing_interval = 0,
|
database_parsing_interval = 0,
|
||||||
correlation_graph_interval = 0;
|
correlation_graph_interval = 0,
|
||||||
|
manual_correlations_parsing_interval = 0;
|
||||||
|
|
||||||
BOOL has_cleanup_interval = false,
|
BOOL has_cleanup_interval = false,
|
||||||
has_stream_expire_interval = false,
|
has_stream_expire_interval = false,
|
||||||
|
@ -420,6 +421,27 @@ static AI_config * AI_parse(char *args)
|
||||||
config->bayesianCorrelationInterval = bayesian_correlation_interval;
|
config->bayesianCorrelationInterval = bayesian_correlation_interval;
|
||||||
_dpd.logMsg( " Bayesian correlation interval: %u\n", config->bayesianCorrelationInterval );
|
_dpd.logMsg( " Bayesian correlation interval: %u\n", config->bayesianCorrelationInterval );
|
||||||
|
|
||||||
|
/* Parsing the manual_correlations_parsing_interval option */
|
||||||
|
if (( arg = (char*) strcasestr( args, "manual_correlations_parsing_interval" ) ))
|
||||||
|
{
|
||||||
|
for ( arg += strlen("manual_correlations_parsing_interval");
|
||||||
|
*arg && (*arg < '0' || *arg > '9');
|
||||||
|
arg++ );
|
||||||
|
|
||||||
|
if ( !(*arg) )
|
||||||
|
{
|
||||||
|
AI_fatal_err ( "manual_correlations_parsing_interval option used but "
|
||||||
|
"no value specified", __FILE__, __LINE__ );
|
||||||
|
}
|
||||||
|
|
||||||
|
manual_correlations_parsing_interval = strtoul ( arg, NULL, 10 );
|
||||||
|
} else {
|
||||||
|
manual_correlations_parsing_interval = DEFAULT_MANUAL_CORRELATIONS_PARSING_INTERVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
config->manualCorrelationsParsingInterval = manual_correlations_parsing_interval;
|
||||||
|
_dpd.logMsg( " Manual correlations parsing interval: %u\n", config->manualCorrelationsParsingInterval );
|
||||||
|
|
||||||
/* Parsing the bayesian_correlation_cache_validity option */
|
/* Parsing the bayesian_correlation_cache_validity option */
|
||||||
if (( arg = (char*) strcasestr( args, "bayesian_correlation_cache_validity" ) ))
|
if (( arg = (char*) strcasestr( args, "bayesian_correlation_cache_validity" ) ))
|
||||||
{
|
{
|
||||||
|
|
6
spp_ai.h
6
spp_ai.h
|
@ -72,6 +72,9 @@
|
||||||
/** Default interval between two alerts (a,b) for considering them correlated */
|
/** Default interval between two alerts (a,b) for considering them correlated */
|
||||||
#define DEFAULT_BAYESIAN_CORRELATION_INTERVAL 1200
|
#define DEFAULT_BAYESIAN_CORRELATION_INTERVAL 1200
|
||||||
|
|
||||||
|
/** Default interval in seconds between an invocation of the thread for parsing XML manual correlations and the next one */
|
||||||
|
#define DEFAULT_MANUAL_CORRELATIONS_PARSING_INTERVAL 120
|
||||||
|
|
||||||
/** Default interval of validity in seconds for an entry in the cache of correlated alerts */
|
/** Default interval of validity in seconds for an entry in the cache of correlated alerts */
|
||||||
#define DEFAULT_BAYESIAN_CORRELATION_CACHE_VALIDITY 600
|
#define DEFAULT_BAYESIAN_CORRELATION_CACHE_VALIDITY 600
|
||||||
|
|
||||||
|
@ -167,6 +170,9 @@ typedef struct
|
||||||
/** Default maximum interval, in seconds, between two alerts for being considered in the same cluster */
|
/** Default maximum interval, in seconds, between two alerts for being considered in the same cluster */
|
||||||
unsigned long clusterMaxAlertInterval;
|
unsigned long clusterMaxAlertInterval;
|
||||||
|
|
||||||
|
/** Interval in seconds between an invocation of the thread for parsing XML manual correlations and the next one */
|
||||||
|
unsigned long manualCorrelationsParsingInterval;
|
||||||
|
|
||||||
/** Interval in seconds for which an entry in the cache of correlated alerts is valid */
|
/** Interval in seconds for which an entry in the cache of correlated alerts is valid */
|
||||||
unsigned long bayesianCorrelationCacheValidity;
|
unsigned long bayesianCorrelationCacheValidity;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue