From e9dd3ebfa20229def9672df00e83ca02f9de5c50 Mon Sep 17 00:00:00 2001 From: BlackLight Date: Tue, 12 Oct 2010 03:12:11 +0200 Subject: [PATCH] Updated documentation and Makefile --- Makefile.am | 14 ++-- Makefile.in | 14 ++-- README | 107 +++++++++++++++++++++++++++--- TODO | 3 +- htdocs/index.html | 26 ++++---- htdocs/js/base64.js | 143 ---------------------------------------- htdocs/js/popup.js | 129 ------------------------------------ schemas/database_ER.png | Bin 0 -> 23082 bytes 8 files changed, 129 insertions(+), 307 deletions(-) delete mode 100644 htdocs/js/base64.js delete mode 100644 htdocs/js/popup.js create mode 100644 schemas/database_ER.png diff --git a/Makefile.am b/Makefile.am index cd0dcb2..d12de53 100644 --- a/Makefile.am +++ b/Makefile.am @@ -47,15 +47,14 @@ doc: doxygen; \ fi -doc-install: - if test ! -z "${DOC_PREFIX}"; then \ - mkdir -p "${DOC_PREFIX}"; \ - cp -r doc/* "${DOC_PREFIX}"; \ -fi - install-data-hook: + if test ! -z "${PWD}/doc"; then \ + mkdir -p "${SHARE_PREFIX}/doc"; \ + cp -r "${PWD}/doc/"* "${SHARE_PREFIX}/doc"; \ +fi mkdir -p "${SHARE_PREFIX}/htdocs" mkdir -p "${SHARE_PREFIX}/htdocs/js" + mkdir -p "${SHARE_PREFIX}/schemas" install -m 0644 "${PWD}/htdocs/index.html" "${SHARE_PREFIX}/htdocs" install -m 0755 "${PWD}/htdocs/pcap.cgi" "${SHARE_PREFIX}/htdocs" install -m 0644 "${PWD}/htdocs/js/Curry-1.0.1.js" "${SHARE_PREFIX}/htdocs/js" @@ -64,3 +63,6 @@ install-data-hook: install -m 0644 "${PWD}/htdocs/js/dracula_graph.js" "${SHARE_PREFIX}/htdocs/js" install -m 0644 "${PWD}/htdocs/js/raphael.js" "${SHARE_PREFIX}/htdocs/js" install -m 0644 "${PWD}/htdocs/js/seedrandom.js" "${SHARE_PREFIX}/htdocs/js" + install -m 0644 "${PWD}/schemas/mysql.sql" "${SHARE_PREFIX}/schemas" + install -m 0644 "${PWD}/schemas/postgresql.sql" "${SHARE_PREFIX}/schemas" + install -m 0644 "${PWD}/schemas/database_ER.png" "${SHARE_PREFIX}/schemas" diff --git a/Makefile.in b/Makefile.in index df02346..03d1867 100644 --- a/Makefile.in +++ b/Makefile.in @@ -823,15 +823,14 @@ doc: doxygen; \ fi -doc-install: - if test ! -z "${DOC_PREFIX}"; then \ - mkdir -p "${DOC_PREFIX}"; \ - cp -r doc/* "${DOC_PREFIX}"; \ -fi - install-data-hook: + if test ! -z "${PWD}/doc"; then \ + mkdir -p "${SHARE_PREFIX}/doc"; \ + cp -r "${PWD}/doc/"* "${SHARE_PREFIX}/doc"; \ +fi mkdir -p "${SHARE_PREFIX}/htdocs" mkdir -p "${SHARE_PREFIX}/htdocs/js" + mkdir -p "${SHARE_PREFIX}/schemas" install -m 0644 "${PWD}/htdocs/index.html" "${SHARE_PREFIX}/htdocs" install -m 0755 "${PWD}/htdocs/pcap.cgi" "${SHARE_PREFIX}/htdocs" install -m 0644 "${PWD}/htdocs/js/Curry-1.0.1.js" "${SHARE_PREFIX}/htdocs/js" @@ -840,6 +839,9 @@ install-data-hook: install -m 0644 "${PWD}/htdocs/js/dracula_graph.js" "${SHARE_PREFIX}/htdocs/js" install -m 0644 "${PWD}/htdocs/js/raphael.js" "${SHARE_PREFIX}/htdocs/js" install -m 0644 "${PWD}/htdocs/js/seedrandom.js" "${SHARE_PREFIX}/htdocs/js" + install -m 0644 "${PWD}/schemas/mysql.sql" "${SHARE_PREFIX}/schemas" + install -m 0644 "${PWD}/schemas/postgresql.sql" "${SHARE_PREFIX}/schemas" + install -m 0644 "${PWD}/schemas/database_ER.png" "${SHARE_PREFIX}/schemas" # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff --git a/README b/README index 702993f..6a541f3 100644 --- a/README +++ b/README @@ -28,7 +28,9 @@ Table of contents: 3.2 Configure options 4. Basic configuration 5. Correlation rules - 6. Additional documentation + 6. Output database + 7. Web interface + 8. Additional documentation =============================== @@ -119,6 +121,14 @@ disabled by the default, and can be enabled by specifying the option --with-postgresql to ./configure. On a Debian-based system you may need to install libpq-dev. +- A DBMS (RECOMMANDED), MySQL and PostgreSQL are supported for now, for writing +clusters, correlations and packet streams information on a DBMS, making the +analysis easier. + +- Perl (OPTIONAL), used for the CGI script in the web interface that saves a +packet stream associated to an alert in .pcap format, to be analyzed by tools +like tcpdump and Wireshark. + ===================== 3.2 Configure options @@ -145,8 +155,6 @@ following: preprocessor ai: \ - hashtable_cleanup_interval 300 \ - tcp_stream_expire_interval 300 \ alertfile "/your/snort/dir/log/alert" \ alert_history_file "/your/snort/dir/log/alert_history" \ alert_serialization_interval 3600 \ @@ -158,9 +166,6 @@ preprocessor ai: \ correlation_rules_dir "/your/snort/dir/etc/corr_rules" \ correlated_alerts_dir "/your/snort/dir/log/correlated_alerts" \ correlation_threshold_coefficient 0.5 \ - database ( type="dbtype", name="snort", user="snortusr", password="snortpass", host="dbhost" ) \ - output_database ( type="dbtype", name="snort", user="snortusr", password="snortpass", host="dbhost" ) \ - database_parsing_interval 30 \ cluster_max_alert_interval 14400 \ clusterfile "/your/snort/dir/log/clustered_alerts" \ cluster ( class="dst_port", name="privileged_ports", range="1-1023" ) \ @@ -170,7 +175,16 @@ preprocessor ai: \ cluster ( class="src_addr", name="vpn_net", range="10.8.0.0/24" ) \ cluster ( class="dst_addr", name="local_net", range="192.168.1.0/24" ) \ cluster ( class="dst_addr", name="dmz_net", range="155.185.0.0/16" ) \ - cluster ( class="dst_addr", name="vpn_net", range="10.8.0.0/24" ) + cluster ( class="dst_addr", name="vpn_net", range="10.8.0.0/24" ) \ + database ( type="dbtype", name="snort", user="snortusr", password="snortpass", host="dbhost" ) \ + database_parsing_interval 30 \ + hashtable_cleanup_interval 300 \ + output_database ( type="dbtype", name="snort", user="snortusr", password="snortpass", host="dbhost" ) \ + tcp_stream_expire_interval 300 \ + webserv_banner "Snort AIPreprocessor module" \ + webserv_dir "/prefix/share/htdocs" \ + webserv_port 7654 + The options are the following: @@ -298,6 +312,19 @@ stream as "expired", if no more packets are received inside of that and it's not "marked" as suspicious (default if not specified: 300 seconds) +- webserv_banner: Banner of the web server, to be placed on the error pages and +in the "Server" HTTP reply header + +- webserver_dir: Directory containing the contents of the web server running +over the module (default if none is specified: +$PREFIX/share/snort_ai_preprocessor/htdocs) + +- webserver_port: Port where the web server will listen (default if none is +specified: 7654). Set this value to 0 if you don't want to run the web server +over the module for having the web interface (in this case, if you want to see +the web graphical visualization of the alerts, you should manually copy the +files contained in htdocs/ in a web server directory) + ==================== 5. Correlation rules ==================== @@ -365,11 +392,73 @@ matching would fail. Any new predicates can be defined as well in hyperalerts, provided that it respects this constraint. +================== +6. Output database +================== + +If the output_database option is specified in the documentation, the alerts, and +the relative clusters, correlations and packet streams information, will be +saved on a database as well. This is strongly suggested, first for making the +management of the module's information easier (a SELECT query needs to be done + for doing also complex searches instead of grep-ing or manually + searching inside of a text file), second because the web interface of +the module can work ONLY if the output_database option is specified (the web + interface strongly depends on the unique IDs assigned to the alerts by + the database interface). Note that for using this option you should +explicitly tell to the ./configure script which DBMS you're going to use, so +that it knows which APIs to use for interfacing with the database, e.g. via +--with-mysql or --with-postgresql. + +After you compile the module, you should pick up the right .sql file from +schemas/ directory (for example mysql.sql or postgresql.sql), or from +$PREFIX/share/snort_ai_preprocessor/schemas after the installation of the +module, and import it in your database, + +$ mysql -uusername -ppassword dbname < schemas/mysql.sql (for MySQL) +$ psql -U username -W dbname < schemas/postgresql.sql (for PostgreSQL) + +You can check the structure of the database from the SQL file for your DBMS, or +from the E/R schema saved in schemas/database_ER.png. + + +================ +7. Web interface +================ + +The module provides an optional (but strongly recommanded) web interface for +browsing the triggered (and already clustered) security alerts, their +correlations and their packet streams information from your browser. This +feature can be switched off by setting the configuration option "webserv_port" +of the module to 0. Otherwise, if none between webserv_dir and webserv_port are +specified, the web server thread starts with the module picking by default the +directory $PREFIX/share/snort_ai_preproc/htdocs as document root and listening +for incoming connections on the port 7654. + +You should use a browser supporting JavaScript, AJAX and SVG technologies in +order to view correctly the alert web interface on your browser (successfully + tested with Firefox 3.5, Chrome and Opera 10), for example, connecting +to the address http://localhost:7654. You can drag and drop the nodes in the +graph, modifying the layout of the graph on the fly or using the "redraw" +function. Each node represents a clustered alert. For viewing the information +over that cluster and the alerts group inside, just click on the node. You can +optionally save the stream of packets associated to a certain alert in .pcap +format (analyzable by tools like tcpdump and Wireshark) from this same +interface. This feature, anyway, is based on the CGI script pcap.cgi inside of +the document root, and it requires the Perl interpreter to be installed on the +machine. + +The web server running over the module is a true web server with its own +document path, so you can use it as stand-alone web server as well and place +your documents and files inside. You can moreover place some CGI scripts or +applications made in the language you prefer, as long as they are files +executable by any users and they have the extension ".cgi". + + =========================== -6. Additional documentation +8. Additional documentation =========================== The additional documentation over the code, functions and data structures can be automatically generated by Doxygen by typing `make doc', and installed in -SNORT_DIR/doc then typing `make doc-install'. +$PREFIX/share/snort_ai_preproc/doc then after `make install'. diff --git a/TODO b/TODO index 567cbe1..6260f11 100644 --- a/TODO +++ b/TODO @@ -6,9 +6,9 @@ AVERAGE/HIGH PRIORITY: - Modules for correlation coefficients - Code profiling - Comment all the code!!! -- Saving packet flows as .pcap - Neural network for computing k - Testing more scenarios, making more hyperalert models +- Manual alert correlation from the web interface ============= LOW PRIORITY: @@ -36,4 +36,5 @@ DONE: + Full PostgreSQL support for output db + Web interface + Function names (private functions with _ or __ ?) ++ Saving packet flows as .pcap diff --git a/htdocs/index.html b/htdocs/index.html index 5802146..5984ca6 100644 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -211,19 +211,19 @@ window.onload = function() { switch ( month ) { - case 'Jan': month = 1; break; - case 'Feb': month = 2; break; - case 'Mar': month = 3; break; - case 'Apr': month = 4; break; - case 'May': month = 5; break; - case 'Jun': month = 6; break; - case 'Jul': month = 7; break; - case 'Ago': month = 8; break; - case 'Sep': month = 9; break; - case 'Oct': month = 10; break; - case 'Nov': month = 11; break; - case 'Dec': month = 12; break; - default : month = 1; break; + case 'Jan': month = 0; break; + case 'Feb': month = 1; break; + case 'Mar': month = 2; break; + case 'Apr': month = 3; break; + case 'May': month = 4; break; + case 'Jun': month = 5; break; + case 'Jul': month = 6; break; + case 'Ago': month = 7; break; + case 'Sep': month = 8; break; + case 'Oct': month = 9; break; + case 'Nov': month = 10; break; + case 'Dec': month = 11; break; + default : month = 0; break; } var timestamp = new Date ( year, month, day, hour, min, sec).getTime().toString(); diff --git a/htdocs/js/base64.js b/htdocs/js/base64.js deleted file mode 100644 index 7504cdd..0000000 --- a/htdocs/js/base64.js +++ /dev/null @@ -1,143 +0,0 @@ -/** -* -* Base64 encode / decode -* http://www.webtoolkit.info/ -* -**/ -  -var Base64 = { -  - // private property - _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", -  - // public method for encoding - encode : function (input) { - var output = ""; - var chr1, chr2, chr3, enc1, enc2, enc3, enc4; - var i = 0; -  - input = Base64._utf8_encode(input); -  - while (i < input.length) { -  - chr1 = input.charCodeAt(i++); - chr2 = input.charCodeAt(i++); - chr3 = input.charCodeAt(i++); -  - enc1 = chr1 >> 2; - enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); - enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); - enc4 = chr3 & 63; -  - if (isNaN(chr2)) { - enc3 = enc4 = 64; - } else if (isNaN(chr3)) { - enc4 = 64; - } -  - output = output + - this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) + - this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4); -  - } -  - return output; - }, -  - // public method for decoding - decode : function (input) { - var output = ""; - var chr1, chr2, chr3; - var enc1, enc2, enc3, enc4; - var i = 0; -  - input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); -  - while (i < input.length) { -  - enc1 = this._keyStr.indexOf(input.charAt(i++)); - enc2 = this._keyStr.indexOf(input.charAt(i++)); - enc3 = this._keyStr.indexOf(input.charAt(i++)); - enc4 = this._keyStr.indexOf(input.charAt(i++)); -  - chr1 = (enc1 << 2) | (enc2 >> 4); - chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); - chr3 = ((enc3 & 3) << 6) | enc4; -  - output = output + String.fromCharCode(chr1); -  - if (enc3 != 64) { - output = output + String.fromCharCode(chr2); - } - if (enc4 != 64) { - output = output + String.fromCharCode(chr3); - } -  - } -  - output = Base64._utf8_decode(output); -  - return output; -  - }, -  - // private method for UTF-8 encoding - _utf8_encode : function (string) { - string = string.replace(/\r\n/g,"\n"); - var utftext = ""; -  - for (var n = 0; n < string.length; n++) { -  - var c = string.charCodeAt(n); -  - if (c < 128) { - utftext += String.fromCharCode(c); - } - else if((c > 127) && (c < 2048)) { - utftext += String.fromCharCode((c >> 6) | 192); - utftext += String.fromCharCode((c & 63) | 128); - } - else { - utftext += String.fromCharCode((c >> 12) | 224); - utftext += String.fromCharCode(((c >> 6) & 63) | 128); - utftext += String.fromCharCode((c & 63) | 128); - } -  - } -  - return utftext; - }, -  - // private method for UTF-8 decoding - _utf8_decode : function (utftext) { - var string = ""; - var i = 0; - var c = c1 = c2 = 0; -  - while ( i < utftext.length ) { -  - c = utftext.charCodeAt(i); -  - if (c < 128) { - string += String.fromCharCode(c); - i++; - } - else if((c > 191) && (c < 224)) { - c2 = utftext.charCodeAt(i+1); - string += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); - i += 2; - } - else { - c2 = utftext.charCodeAt(i+1); - c3 = utftext.charCodeAt(i+2); - string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); - i += 3; - } -  - } -  - return string; - } -  -} - diff --git a/htdocs/js/popup.js b/htdocs/js/popup.js deleted file mode 100644 index c491170..0000000 --- a/htdocs/js/popup.js +++ /dev/null @@ -1,129 +0,0 @@ -var dom = (document.getElementById) ? true : false; -var ns5 = ((navigator.userAgent.indexOf("Gecko")>-1) && dom) ? true: false; -var ie5 = ((navigator.userAgent.indexOf("MSIE")>-1) && dom) ? true : false; -var ns4 = (document.layers && !dom) ? true : false; -var ie4 = (document.all && !dom) ? true : false; -var nodyn = (!ns5 && !ns4 && !ie4 && !ie5) ? true : false; - -var origWidth, origHeight; -if (ns4) { - origWidth = window.innerWidth; origHeight = window.innerHeight; - window.onresize = function() { if (window.innerWidth != origWidth || window.innerHeight != origHeight) history.go(0); } -} - -if (nodyn) { event = "nope" } -var tipFollowMouse = true; -var tipWidth = 160; -var offX = 12; // how far from mouse to show tip -var offY = 12; -var tipFontFamily = "Verdana, arial, helvetica, sans-serif"; -var tipFontSize = "8pt"; -var tipFontColor = "#000000"; -var tipBgColor = "#DDECFF"; -var origBgColor = tipBgColor; // in case no bgColor set in array -var tipBorderColor = "#000080"; -var tipBorderWidth = 2; -var tipBorderStyle = "ridge"; -var tipPadding = 4; - -var messages = new Array(); -messages[0] = new Array('http://planmagic.com/images/plmbiz.jpg','Professional business planning software.',"#FFFFFF"); -messages[1] = new Array('http://planmagic.com/images/plmmar.jpg','Professional marketing planning software.',"#DDECFF"); -messages[2] = new Array('http://planmagic.com/images/plmfinance.jpg','Financial calculations and projections made easy.',"#E9E9E9"); - -if (document.images) { - var theImgs = new Array(); - for (var i=0; i'; -var endStr = ''; - -var tooltip, tipcss; -function initTip() { - if (nodyn) return; - tooltip = (ns4)? document.tipDiv.document: (ie4)? document.all['tipDiv']: (ie5||ns5)? document.getElementById('tipDiv'): null; - tipcss = (ns4)? document.tipDiv: tooltip.style; - if (ie4||ie5||ns5) { // ns4 would lose all this on rewrites - tipcss.width = tipWidth+"px"; - tipcss.fontFamily = tipFontFamily; - tipcss.fontSize = tipFontSize; - tipcss.color = tipFontColor; - tipcss.backgroundColor = tipBgColor; - tipcss.borderColor = tipBorderColor; - tipcss.borderWidth = tipBorderWidth+"px"; - tipcss.padding = tipPadding+"px"; - tipcss.borderStyle = tipBorderStyle; - } - if (tooltip&&tipFollowMouse) { - if (ns4) document.captureEvents(Event.MOUSEMOVE); - document.onmousemove = trackMouse; - } -} - -window.onload = initTip; - -var t1,t2; // for setTimeouts -var tipOn = false; // check if over tooltip link -function doTooltip(evt,num) { - - if (!tooltip) return; - if (t1) clearTimeout(t1); if (t2) clearTimeout(t2); - tipOn = true; - // set colors if included in messages array - if (messages[num][2]) var curBgColor = messages[num][2]; - else curBgColor = tipBgColor; - if (messages[num][3]) var curFontColor = messages[num][3]; - else curFontColor = tipFontColor; - if (ns4) { - var tip = '
'+ startStr + messages[num][0] + midStr + '' + messages[num][1] + '' + endStr + '
'; - tooltip.write(tip); - tooltip.close(); - } else if (ie4||ie5||ns5) { - var tip = startStr + messages[num][0] + midStr + '' + messages[num][1] + '' + endStr; - tipcss.backgroundColor = curBgColor; - tooltip.innerHTML = tip; - } - if (!tipFollowMouse) positionTip(evt); - else t1=setTimeout("tipcss.visibility='visible'",100); -} - -var mouseX, mouseY; -function trackMouse(evt) { - mouseX = (ns4||ns5)? evt.pageX: window.event.clientX + document.body.scrollLeft; - mouseY = (ns4||ns5)? evt.pageY: window.event.clientY + document.body.scrollTop; - if (tipOn) positionTip(evt); -} - -function positionTip(evt) { - if (!tipFollowMouse) { - mouseX = (ns4||ns5)? evt.pageX: window.event.clientX + document.body.scrollLeft; - mouseY = (ns4||ns5)? evt.pageY: window.event.clientY + document.body.scrollTop; - } - // tooltip width and height - var tpWd = (ns4)? tooltip.width: (ie4||ie5)? tooltip.clientWidth: tooltip.offsetWidth; - var tpHt = (ns4)? tooltip.height: (ie4||ie5)? tooltip.clientHeight: tooltip.offsetHeight; - // document area in view (subtract scrollbar width for ns) - var winWd = (ns4||ns5)? window.innerWidth-20+window.pageXOffset: document.body.clientWidth+document.body.scrollLeft; - var winHt = (ns4||ns5)? window.innerHeight-20+window.pageYOffset: document.body.clientHeight+document.body.scrollTop; - // check mouse position against tip and window dimensions - // and position the tooltip - if ((mouseX+offX+tpWd)>winWd) - tipcss.left = (ns4)? mouseX-(tpWd+offX): mouseX-(tpWd+offX)+"px"; - else tipcss.left = (ns4)? mouseX+offX: mouseX+offX+"px"; - if ((mouseY+offY+tpHt)>winHt) - tipcss.top = (ns4)? winHt-(tpHt+offY): winHt-(tpHt+offY)+"px"; - else tipcss.top = (ns4)? mouseY+offY: mouseY+offY+"px"; - if (!tipFollowMouse) t1=setTimeout("tipcss.visibility='visible'",100); -} - -function hideTip() { - if (!tooltip) return; - t2=setTimeout("tipcss.visibility='hidden'",100); - tipOn = false; -} - diff --git a/schemas/database_ER.png b/schemas/database_ER.png new file mode 100644 index 0000000000000000000000000000000000000000..b4513a2e3a0bf4fe2f78a2de1a86d3d50b945062 GIT binary patch literal 23082 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 z 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 UbB2+#;53j`p00i_>zopr049z5MF0Q* literal 0 HcmV?d00001