mirror of
https://github.com/zeek/zeek.git
synced 2025-10-12 03:28:19 +00:00
Reorganize documentation index
Moved examples and use cases into a common subdir so those topics will get grouped together in the main sidebar/TOC
This commit is contained in:
parent
b1b7027982
commit
c46b018fdb
46 changed files with 27 additions and 16 deletions
24
doc/examples/httpmonitor/file_extraction.bro
Normal file
24
doc/examples/httpmonitor/file_extraction.bro
Normal file
|
@ -0,0 +1,24 @@
|
|||
|
||||
global mime_to_ext: table[string] of string = {
|
||||
["application/x-dosexec"] = "exe",
|
||||
["text/plain"] = "txt",
|
||||
["image/jpeg"] = "jpg",
|
||||
["image/png"] = "png",
|
||||
["text/html"] = "html",
|
||||
};
|
||||
|
||||
event file_sniff(f: fa_file, meta: fa_metadata)
|
||||
{
|
||||
if ( f$source != "HTTP" )
|
||||
return;
|
||||
|
||||
if ( ! meta?$mime_type )
|
||||
return;
|
||||
|
||||
if ( meta$mime_type !in mime_to_ext )
|
||||
return;
|
||||
|
||||
local fname = fmt("%s-%s.%s", f$source, f$id, mime_to_ext[meta$mime_type]);
|
||||
print fmt("Extracting file %s", fname);
|
||||
Files::add_analyzer(f, Files::ANALYZER_EXTRACT, [$extract_filename=fname]);
|
||||
}
|
5
doc/examples/httpmonitor/http_proxy_01.bro
Normal file
5
doc/examples/httpmonitor/http_proxy_01.bro
Normal file
|
@ -0,0 +1,5 @@
|
|||
event http_reply(c: connection, version: string, code: count, reason: string)
|
||||
{
|
||||
if ( /^[hH][tT][tT][pP]:/ in c$http$uri && c$http$status_code == 200 )
|
||||
print fmt("A local server is acting as an open proxy: %s", c$id$resp_h);
|
||||
}
|
26
doc/examples/httpmonitor/http_proxy_02.bro
Normal file
26
doc/examples/httpmonitor/http_proxy_02.bro
Normal file
|
@ -0,0 +1,26 @@
|
|||
|
||||
module HTTP;
|
||||
|
||||
export {
|
||||
|
||||
global success_status_codes: set[count] = {
|
||||
200,
|
||||
201,
|
||||
202,
|
||||
203,
|
||||
204,
|
||||
205,
|
||||
206,
|
||||
207,
|
||||
208,
|
||||
226,
|
||||
304
|
||||
};
|
||||
}
|
||||
|
||||
event http_reply(c: connection, version: string, code: count, reason: string)
|
||||
{
|
||||
if ( /^[hH][tT][tT][pP]:/ in c$http$uri &&
|
||||
c$http$status_code in HTTP::success_status_codes )
|
||||
print fmt("A local server is acting as an open proxy: %s", c$id$resp_h);
|
||||
}
|
31
doc/examples/httpmonitor/http_proxy_03.bro
Normal file
31
doc/examples/httpmonitor/http_proxy_03.bro
Normal file
|
@ -0,0 +1,31 @@
|
|||
|
||||
@load base/utils/site
|
||||
|
||||
redef Site::local_nets += { 192.168.0.0/16 };
|
||||
|
||||
module HTTP;
|
||||
|
||||
export {
|
||||
|
||||
global success_status_codes: set[count] = {
|
||||
200,
|
||||
201,
|
||||
202,
|
||||
203,
|
||||
204,
|
||||
205,
|
||||
206,
|
||||
207,
|
||||
208,
|
||||
226,
|
||||
304
|
||||
};
|
||||
}
|
||||
|
||||
event http_reply(c: connection, version: string, code: count, reason: string)
|
||||
{
|
||||
if ( Site::is_local_addr(c$id$resp_h) &&
|
||||
/^[hH][tT][tT][pP]:/ in c$http$uri &&
|
||||
c$http$status_code in HTTP::success_status_codes )
|
||||
print fmt("A local server is acting as an open proxy: %s", c$id$resp_h);
|
||||
}
|
40
doc/examples/httpmonitor/http_proxy_04.bro
Normal file
40
doc/examples/httpmonitor/http_proxy_04.bro
Normal file
|
@ -0,0 +1,40 @@
|
|||
@load base/utils/site
|
||||
@load base/frameworks/notice
|
||||
|
||||
redef Site::local_nets += { 192.168.0.0/16 };
|
||||
|
||||
module HTTP;
|
||||
|
||||
export {
|
||||
|
||||
redef enum Notice::Type += {
|
||||
Open_Proxy
|
||||
};
|
||||
|
||||
global success_status_codes: set[count] = {
|
||||
200,
|
||||
201,
|
||||
202,
|
||||
203,
|
||||
204,
|
||||
205,
|
||||
206,
|
||||
207,
|
||||
208,
|
||||
226,
|
||||
304
|
||||
};
|
||||
}
|
||||
|
||||
event http_reply(c: connection, version: string, code: count, reason: string)
|
||||
{
|
||||
if ( Site::is_local_addr(c$id$resp_h) &&
|
||||
/^[hH][tT][tT][pP]:/ in c$http$uri &&
|
||||
c$http$status_code in HTTP::success_status_codes )
|
||||
NOTICE([$note=HTTP::Open_Proxy,
|
||||
$msg=fmt("A local server is acting as an open proxy: %s",
|
||||
c$id$resp_h),
|
||||
$conn=c,
|
||||
$identifier=cat(c$id$resp_h),
|
||||
$suppress_for=1day]);
|
||||
}
|
196
doc/examples/httpmonitor/index.rst
Normal file
196
doc/examples/httpmonitor/index.rst
Normal file
|
@ -0,0 +1,196 @@
|
|||
|
||||
.. _http-monitor:
|
||||
|
||||
=======================
|
||||
Monitoring HTTP Traffic
|
||||
=======================
|
||||
|
||||
Bro can be used to log the entire HTTP traffic from your network to the
|
||||
http.log file. This file can then be used for analysis and auditing
|
||||
purposes.
|
||||
|
||||
In the sections below we briefly explain the structure of the http.log
|
||||
file, then we show you how to perform basic HTTP traffic monitoring and
|
||||
analysis tasks with Bro. Some of these ideas and techniques can later be
|
||||
applied to monitor different protocols in a similar way.
|
||||
|
||||
----------------------------
|
||||
Introduction to the HTTP log
|
||||
----------------------------
|
||||
|
||||
The http.log file contains a summary of all HTTP requests and responses
|
||||
sent over a Bro-monitored network. Here are the first few columns of
|
||||
``http.log``::
|
||||
|
||||
# ts uid orig_h orig_p resp_h resp_p
|
||||
1311627961.8 HSH4uV8KVJg 192.168.1.100 52303 192.150.187.43 80
|
||||
|
||||
Every single line in this log starts with a timestamp, a unique
|
||||
connection identifier (UID), and a connection 4-tuple (originator
|
||||
host/port and responder host/port). The UID can be used to identify all
|
||||
logged activity (possibly across multiple log files) associated with a
|
||||
given connection 4-tuple over its lifetime.
|
||||
|
||||
The remaining columns detail the activity that's occurring. For
|
||||
example, the columns on the line below (shortened for brevity) show a
|
||||
request to the root of Bro website::
|
||||
|
||||
# method host uri referrer user_agent
|
||||
GET bro.org / - <...>Chrome/12.0.742.122<...>
|
||||
|
||||
Network administrators and security engineers, for instance, can use the
|
||||
information in this log to understand the HTTP activity on the network
|
||||
and troubleshoot network problems or search for anomalous activities. We must
|
||||
stress that there is no single right way to perform an analysis. It will
|
||||
depend on the expertise of the person performing the analysis and the
|
||||
specific details of the task.
|
||||
|
||||
For more information about how to handle the HTTP protocol in Bro,
|
||||
including a complete list of the fields available in http.log, go to
|
||||
Bro's :doc:`HTTP script reference
|
||||
</scripts/base/protocols/http/main.bro>`.
|
||||
|
||||
------------------------
|
||||
Detecting a Proxy Server
|
||||
------------------------
|
||||
|
||||
A proxy server is a device on your network configured to request a
|
||||
service on behalf of a third system; one of the most common examples is
|
||||
a Web proxy server. A client without Internet access connects to the
|
||||
proxy and requests a web page, the proxy sends the request to the web
|
||||
server, which receives the response, and passes it to the original
|
||||
client.
|
||||
|
||||
Proxies were conceived to help manage a network and provide better
|
||||
encapsulation. Proxies by themselves are not a security threat, but a
|
||||
misconfigured or unauthorized proxy can allow others, either inside or
|
||||
outside the network, to access any web site and even conduct malicious
|
||||
activities anonymously using the network's resources.
|
||||
|
||||
What Proxy Server traffic looks like
|
||||
-------------------------------------
|
||||
|
||||
In general, when a client starts talking with a proxy server, the
|
||||
traffic consists of two parts: (i) a GET request, and (ii) an HTTP/
|
||||
reply::
|
||||
|
||||
Request: GET http://www.bro.org/ HTTP/1.1
|
||||
Reply: HTTP/1.0 200 OK
|
||||
|
||||
This will differ from traffic between a client and a normal Web server
|
||||
because GET requests should not include "http" on the string. So we can
|
||||
use this to identify a proxy server.
|
||||
|
||||
We can write a basic script in Bro to handle the http_reply event and
|
||||
detect a reply for a ``GET http://`` request.
|
||||
|
||||
.. literalinclude:: http_proxy_01.bro
|
||||
:caption:
|
||||
:language: bro
|
||||
:linenos:
|
||||
|
||||
.. sourcecode:: console
|
||||
|
||||
$ bro -r http/proxy.pcap http_proxy_01.bro
|
||||
A local server is acting as an open proxy: 192.168.56.101
|
||||
|
||||
Basically, the script is checking for a "200 OK" status code on a reply
|
||||
for a request that includes "http:" (case insensitive). In reality, the
|
||||
HTTP protocol defines several success status codes other than 200, so we
|
||||
will extend our basic script to also consider the additional codes.
|
||||
|
||||
.. literalinclude:: http_proxy_02.bro
|
||||
:caption:
|
||||
:language: bro
|
||||
:linenos:
|
||||
|
||||
.. sourcecode:: console
|
||||
|
||||
$ bro -r http/proxy.pcap http_proxy_02.bro
|
||||
A local server is acting as an open proxy: 192.168.56.101
|
||||
|
||||
Next, we will make sure that the responding proxy is part of our local
|
||||
network.
|
||||
|
||||
.. literalinclude:: http_proxy_03.bro
|
||||
:caption:
|
||||
:language: bro
|
||||
:linenos:
|
||||
|
||||
.. sourcecode:: console
|
||||
|
||||
$ bro -r http/proxy.pcap http_proxy_03.bro
|
||||
A local server is acting as an open proxy: 192.168.56.101
|
||||
|
||||
.. note::
|
||||
|
||||
The redefinition of :bro:see:`Site::local_nets` is only done inside
|
||||
this script to make it a self-contained example. It's typically
|
||||
redefined somewhere else.
|
||||
|
||||
Finally, our goal should be to generate an alert when a proxy has been
|
||||
detected instead of printing a message on the console output. For that,
|
||||
we will tag the traffic accordingly and define a new ``Open_Proxy``
|
||||
``Notice`` type to alert of all tagged communications. Once a
|
||||
notification has been fired, we will further suppress it for one day.
|
||||
Below is the complete script.
|
||||
|
||||
.. literalinclude:: http_proxy_04.bro
|
||||
:caption:
|
||||
:language: bro
|
||||
:linenos:
|
||||
|
||||
.. sourcecode:: console
|
||||
|
||||
$ bro -r http/proxy.pcap http_proxy_04.bro
|
||||
$ cat notice.log
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path notice
|
||||
#open 2018-12-13-22-56-39
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p fuid file_mime_type file_desc proto note msg sub src dst p n peer_descr actions suppress_for dropped remote_location.country_code remote_location.region remote_location.city remote_location.latitude remote_location.longitude
|
||||
#types time string addr port addr port string string string enum enum string string addr addr port count string set[enum] interval bool string string string double double
|
||||
1389654450.449603 CHhAvVGS1DHFjwGM9 192.168.56.1 52679 192.168.56.101 80 - - - tcp HTTP::Open_Proxy A local server is acting as an open proxy: 192.168.56.101 - 192.168.56.1 192.168.56.101 80 - - Notice::ACTION_LOG 86400.000000 F - - - - -
|
||||
#close 2018-12-13-22-56-40
|
||||
|
||||
Note that this script only logs the presence of the proxy to
|
||||
``notice.log``, but if an additional email is desired (and email
|
||||
functionality is enabled), then that's done simply by redefining
|
||||
:bro:see:`Notice::emailed_types` to add the ``Open_proxy`` notice type
|
||||
to it.
|
||||
|
||||
----------------
|
||||
Inspecting Files
|
||||
----------------
|
||||
|
||||
Files are often transmitted on regular HTTP conversations between a
|
||||
client and a server. Most of the time these files are harmless, just
|
||||
images and some other multimedia content, but there are also types of
|
||||
files, specially executable files, that can damage your system. We can
|
||||
instruct Bro to create a copy of all files of certain types that it sees
|
||||
using the :ref:`File Analysis Framework <file-analysis-framework>`
|
||||
(introduced with Bro 2.2):
|
||||
|
||||
.. literalinclude:: file_extraction.bro
|
||||
:caption:
|
||||
:language: bro
|
||||
:linenos:
|
||||
|
||||
.. sourcecode:: console
|
||||
|
||||
$ bro -r bro.org.pcap file_extraction.bro
|
||||
Extracting file HTTP-FiIpIB2hRQSDBOSJRg.html
|
||||
Extracting file HTTP-FMG4bMmVV64eOsCb.txt
|
||||
Extracting file HTTP-FnaT2a3UDd093opCB9.txt
|
||||
Extracting file HTTP-FfQGqj4Fhh3pH7nVQj.txt
|
||||
Extracting file HTTP-FsvATF146kf1Emc21j.txt
|
||||
[...]
|
||||
|
||||
Here, the ``mime_to_ext`` table serves two purposes. It defines which
|
||||
mime types to extract and also the file suffix of the extracted files.
|
||||
Extracted files are written to a new ``extract_files`` subdirectory.
|
||||
Also note that the first conditional in the :bro:see:`file_new` event
|
||||
handler can be removed to make this behavior generic to other protocols
|
||||
besides HTTP.
|
203
doc/examples/ids/index.rst
Normal file
203
doc/examples/ids/index.rst
Normal file
|
@ -0,0 +1,203 @@
|
|||
|
||||
.. _bro-ids:
|
||||
|
||||
===
|
||||
IDS
|
||||
===
|
||||
|
||||
An Intrusion Detection System (IDS) allows you to detect suspicious
|
||||
activities happening on your network as a result of a past or active
|
||||
attack. Because of its programming capabilities, Bro can easily be
|
||||
configured to behave like traditional IDSs and detect common attacks
|
||||
with well known patterns, or you can create your own scripts to detect
|
||||
conditions specific to your particular case.
|
||||
|
||||
In the following sections, we present a few examples of common uses of
|
||||
Bro as an IDS.
|
||||
|
||||
-------------------------------------------------
|
||||
Detecting an FTP Brute-force Attack and Notifying
|
||||
-------------------------------------------------
|
||||
|
||||
For the purpose of this exercise, we define FTP brute-forcing as too many
|
||||
rejected usernames and passwords occurring from a single address. We
|
||||
start by defining a threshold for the number of attempts, a monitoring
|
||||
interval (in minutes), and a new notice type.
|
||||
|
||||
.. sourcecode:: bro
|
||||
:caption: detect-bruteforcing.bro
|
||||
|
||||
module FTP;
|
||||
|
||||
export {
|
||||
redef enum Notice::Type += {
|
||||
## Indicates a host bruteforcing FTP logins by watching for too
|
||||
## many rejected usernames or failed passwords.
|
||||
Bruteforcing
|
||||
};
|
||||
|
||||
## How many rejected usernames or passwords are required before being
|
||||
## considered to be bruteforcing.
|
||||
const bruteforce_threshold: double = 20 &redef;
|
||||
|
||||
## The time period in which the threshold needs to be crossed before
|
||||
## being reset.
|
||||
const bruteforce_measurement_interval = 15mins &redef;
|
||||
}
|
||||
|
||||
Using the ftp_reply event, we check for error codes from the `500
|
||||
series <http://en.wikipedia.org/wiki/List_of_FTP_server_return_codes>`_
|
||||
for the "USER" and "PASS" commands, representing rejected usernames or
|
||||
passwords. For this, we can use the :bro:see:`FTP::parse_ftp_reply_code`
|
||||
function to break down the reply code and check if the first digit is a
|
||||
"5" or not. If true, we then use the :ref:`Summary Statistics Framework
|
||||
<sumstats-framework>` to keep track of the number of failed attempts.
|
||||
|
||||
.. sourcecode:: bro
|
||||
:caption: detect-bruteforcing.bro
|
||||
|
||||
event ftp_reply(c: connection, code: count, msg: string, cont_resp: bool)
|
||||
{
|
||||
local cmd = c$ftp$cmdarg$cmd;
|
||||
if ( cmd == "USER" || cmd == "PASS" )
|
||||
{
|
||||
if ( FTP::parse_ftp_reply_code(code)$x == 5 )
|
||||
SumStats::observe("ftp.failed_auth", [$host=c$id$orig_h], [$str=cat(c$id$resp_h)]);
|
||||
}
|
||||
}
|
||||
|
||||
Next, we use the SumStats framework to raise a notice of the attack when
|
||||
the number of failed attempts exceeds the specified threshold during the
|
||||
measuring interval.
|
||||
|
||||
.. sourcecode:: bro
|
||||
:caption: detect-bruteforcing.bro
|
||||
|
||||
event bro_init()
|
||||
{
|
||||
local r1: SumStats::Reducer = [$stream="ftp.failed_auth", $apply=set(SumStats::UNIQUE), $unique_max=double_to_count(bruteforce_threshold+2)];
|
||||
SumStats::create([$name="ftp-detect-bruteforcing",
|
||||
$epoch=bruteforce_measurement_interval,
|
||||
$reducers=set(r1),
|
||||
$threshold_val(key: SumStats::Key, result: SumStats::Result) =
|
||||
{
|
||||
return result["ftp.failed_auth"]$num+0.0;
|
||||
},
|
||||
$threshold=bruteforce_threshold,
|
||||
$threshold_crossed(key: SumStats::Key, result: SumStats::Result) =
|
||||
{
|
||||
local r = result["ftp.failed_auth"];
|
||||
local dur = duration_to_mins_secs(r$end-r$begin);
|
||||
local plural = r$unique>1 ? "s" : "";
|
||||
local message = fmt("%s had %d failed logins on %d FTP server%s in %s", key$host, r$num, r$unique, plural, dur);
|
||||
NOTICE([$note=FTP::Bruteforcing,
|
||||
$src=key$host,
|
||||
$msg=message,
|
||||
$identifier=cat(key$host)]);
|
||||
}]);
|
||||
}
|
||||
|
||||
Below is the final code for our script.
|
||||
|
||||
.. sourcecode:: bro
|
||||
:caption: detect-bruteforcing.bro
|
||||
|
||||
##! FTP brute-forcing detector, triggering when too many rejected usernames or
|
||||
##! failed passwords have occurred from a single address.
|
||||
|
||||
@load base/protocols/ftp
|
||||
@load base/frameworks/sumstats
|
||||
|
||||
@load base/utils/time
|
||||
|
||||
module FTP;
|
||||
|
||||
export {
|
||||
redef enum Notice::Type += {
|
||||
## Indicates a host bruteforcing FTP logins by watching for too
|
||||
## many rejected usernames or failed passwords.
|
||||
Bruteforcing
|
||||
};
|
||||
|
||||
## How many rejected usernames or passwords are required before being
|
||||
## considered to be bruteforcing.
|
||||
const bruteforce_threshold: double = 20 &redef;
|
||||
|
||||
## The time period in which the threshold needs to be crossed before
|
||||
## being reset.
|
||||
const bruteforce_measurement_interval = 15mins &redef;
|
||||
}
|
||||
|
||||
|
||||
event bro_init()
|
||||
{
|
||||
local r1: SumStats::Reducer = [$stream="ftp.failed_auth", $apply=set(SumStats::UNIQUE), $unique_max=double_to_count(bruteforce_threshold+2)];
|
||||
SumStats::create([$name="ftp-detect-bruteforcing",
|
||||
$epoch=bruteforce_measurement_interval,
|
||||
$reducers=set(r1),
|
||||
$threshold_val(key: SumStats::Key, result: SumStats::Result) =
|
||||
{
|
||||
return result["ftp.failed_auth"]$num+0.0;
|
||||
},
|
||||
$threshold=bruteforce_threshold,
|
||||
$threshold_crossed(key: SumStats::Key, result: SumStats::Result) =
|
||||
{
|
||||
local r = result["ftp.failed_auth"];
|
||||
local dur = duration_to_mins_secs(r$end-r$begin);
|
||||
local plural = r$unique>1 ? "s" : "";
|
||||
local message = fmt("%s had %d failed logins on %d FTP server%s in %s", key$host, r$num, r$unique, plural, dur);
|
||||
NOTICE([$note=FTP::Bruteforcing,
|
||||
$src=key$host,
|
||||
$msg=message,
|
||||
$identifier=cat(key$host)]);
|
||||
}]);
|
||||
}
|
||||
|
||||
event ftp_reply(c: connection, code: count, msg: string, cont_resp: bool)
|
||||
{
|
||||
local cmd = c$ftp$cmdarg$cmd;
|
||||
if ( cmd == "USER" || cmd == "PASS" )
|
||||
{
|
||||
if ( FTP::parse_ftp_reply_code(code)$x == 5 )
|
||||
SumStats::observe("ftp.failed_auth", [$host=c$id$orig_h], [$str=cat(c$id$resp_h)]);
|
||||
}
|
||||
}
|
||||
|
||||
.. sourcecode:: console
|
||||
|
||||
$ bro -r ftp/bruteforce.pcap protocols/ftp/detect-bruteforcing.bro
|
||||
$ cat notice.log
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path notice
|
||||
#open 2018-12-13-22-56-21
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p fuid file_mime_type file_desc proto note msg sub src dst p n peer_descr actions suppress_for dropped remote_location.country_code remote_location.region remote_location.city remote_location.latitude remote_location.longitude
|
||||
#types time string addr port addr port string string string enum enum string string addr addr port count string set[enum] interval bool string string string double double
|
||||
1389721084.522861 - - - - - - - - - FTP::Bruteforcing 192.168.56.1 had 20 failed logins on 1 FTP server in 0m37s - 192.168.56.1 - - - - Notice::ACTION_LOG 3600.000000 F - - - - -
|
||||
#close 2018-12-13-22-56-21
|
||||
|
||||
As a final note, the :doc:`detect-bruteforcing.bro
|
||||
</scripts/policy/protocols/ftp/detect-bruteforcing.bro>` script above is
|
||||
included with Bro out of the box. Use this feature by loading this script
|
||||
during startup.
|
||||
|
||||
-------------
|
||||
Other Attacks
|
||||
-------------
|
||||
|
||||
Detecting SQL Injection Attacks
|
||||
-------------------------------
|
||||
|
||||
Checking files against known malware hashes
|
||||
-------------------------------------------
|
||||
|
||||
Files transmitted on your network could either be completely harmless or
|
||||
contain viruses and other threats. One possible action against this
|
||||
threat is to compute the hashes of the files and compare them against a
|
||||
list of known malware hashes. Bro simplifies this task by offering a
|
||||
:doc:`detect-MHR.bro </scripts/policy/frameworks/files/detect-MHR.bro>`
|
||||
script that creates and compares hashes against the `Malware Hash
|
||||
Registry <https://www.team-cymru.org/Services/MHR/>`_ maintained by Team
|
||||
Cymru. Use this feature by loading this script during startup.
|
13
doc/examples/index.rst
Normal file
13
doc/examples/index.rst
Normal file
|
@ -0,0 +1,13 @@
|
|||
|
||||
======================
|
||||
Examples and Use Cases
|
||||
======================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
logs/index.rst
|
||||
httpmonitor/index.rst
|
||||
ids/index.rst
|
||||
mimestats/index.rst
|
||||
scripting/index.rst
|
308
doc/examples/logs/index.rst
Normal file
308
doc/examples/logs/index.rst
Normal file
|
@ -0,0 +1,308 @@
|
|||
|
||||
.. _bro-logging:
|
||||
|
||||
=======
|
||||
Logging
|
||||
=======
|
||||
|
||||
Once Bro has been deployed in an environment and monitoring live
|
||||
traffic, it will, in its default configuration, begin to produce
|
||||
human-readable ASCII logs. Each log file, produced by Bro's
|
||||
:ref:`framework-logging`, is populated with organized, mostly
|
||||
connection-oriented data. As the standard log files are simple ASCII
|
||||
data, working with the data contained in them can be done from a
|
||||
command line terminal once you have been familiarized with the types
|
||||
of data that can be found in each file. In the following, we work
|
||||
through the logs general structure and then examine some standard ways
|
||||
of working with them.
|
||||
|
||||
----------------------
|
||||
Working with Log Files
|
||||
----------------------
|
||||
|
||||
Generally, all of Bro's log files are produced by a corresponding
|
||||
script that defines their individual structure. However, as each log
|
||||
file flows through the Logging Framework, they share a set of
|
||||
structural similarities. Without breaking into the scripting aspect of
|
||||
Bro here, a bird's eye view of how the log files are produced
|
||||
progresses as follows. The script's author defines the kinds of data,
|
||||
such as the originating IP address or the duration of a connection,
|
||||
which will make up the fields (i.e., columns) of the log file. The
|
||||
author then decides what network activity should generate a single log
|
||||
file entry (i.e., one line). For example, this could be a connection
|
||||
having been completed or an HTTP ``GET`` request being issued by an
|
||||
originator. When these behaviors are observed during operation, the
|
||||
data is passed to the Logging Framework which adds the entry
|
||||
to the appropriate log file.
|
||||
|
||||
As the fields of the log entries can be further customized by the
|
||||
user, the Logging Framework makes use of a header block to ensure that
|
||||
it remains self-describing. Here's the first few lines of a ``conn.log``.
|
||||
|
||||
.. sourcecode:: console
|
||||
|
||||
$ cat conn.log
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path conn
|
||||
#open 2018-12-10-22-18-00
|
||||
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state local_orig local_resp missed_bytes history orig_pkts orig_ip_bytes resp_pkts resp_ip_bytes tunnel_parents
|
||||
#types time string addr port addr port enum string interval count count string bool bool count string count count count count set[string]
|
||||
1300475167.096535 CHhAvVGS1DHFjwGM9 141.142.220.202 5353 224.0.0.251 5353 udp dns - - - S0 - - 0 D 1 73 0 0 -
|
||||
1300475167.097012 ClEkJM2Vm5giqnMf4h fe80::217:f2ff:fed7:cf65 5353 ff02::fb 5353 udp dns - - - S0 - - 0 D 1 199 0 0 -
|
||||
1300475167.099816 C4J4Th3PJpwUYZZ6gc 141.142.220.50 5353 224.0.0.251 5353 udp dns - - - S0 - - 0 D 1 179 0 0 -
|
||||
[...]
|
||||
|
||||
As you can see, the header consists of lines prefixed by ``#`` and
|
||||
includes information such as what separators are being used for
|
||||
various types of data, what an empty field looks like and what an
|
||||
unset field looks like. In this example, the default TAB separator is
|
||||
being used as the delimiter between fields (``\x09`` is the tab
|
||||
character in hex). It also lists the comma as the separator for set
|
||||
data, the string ``(empty)`` as the indicator for an empty field and
|
||||
the ``-`` character as the indicator for a field that hasn't been set.
|
||||
The timestamp for when the file was created is included under
|
||||
``#open``. The header then goes on to detail the fields being listed
|
||||
in the file and the data types of those fields, in ``#fields`` and
|
||||
``#types``, respectively. These two entries are often the two most
|
||||
significant points of interest as they detail not only the field names
|
||||
but the data types used. When navigating through the different log
|
||||
files with tools like ``sed``, ``awk``, or ``grep``, having the field
|
||||
definitions readily available saves the user some mental leg work. The
|
||||
field names are also a key resource for using the :ref:`bro-cut
|
||||
<bro-cut>` utility included with Bro, see below.
|
||||
|
||||
Next to the header follows the main content. In this example we see 7
|
||||
connections with their key properties, such as originator and
|
||||
responder IP addresses (note how Bro transparently handles both IPv4 and
|
||||
IPv6), transport-layer ports, application-layer services ( - the
|
||||
``service`` field is filled in as Bro determines a specific protocol to
|
||||
be in use, independent of the connection's ports), payload size, and
|
||||
more. See :bro:type:`Conn::Info` for a description of all fields.
|
||||
|
||||
In addition to ``conn.log``, Bro generates many further logs by
|
||||
default, including:
|
||||
|
||||
``dpd.log``
|
||||
A summary of protocols encountered on non-standard ports.
|
||||
|
||||
``dns.log``
|
||||
All DNS activity.
|
||||
|
||||
``ftp.log``
|
||||
A log of FTP session-level activity.
|
||||
|
||||
``files.log``
|
||||
Summaries of files transferred over the network. This information
|
||||
is aggregated from different protocols, including HTTP, FTP, and
|
||||
SMTP.
|
||||
|
||||
``http.log``
|
||||
A summary of all HTTP requests with their replies.
|
||||
|
||||
``known_certs.log``
|
||||
SSL certificates seen in use.
|
||||
|
||||
``smtp.log``
|
||||
A summary of SMTP activity.
|
||||
|
||||
``ssl.log``
|
||||
A record of SSL sessions, including certificates being used.
|
||||
|
||||
``weird.log``
|
||||
A log of unexpected protocol-level activity. Whenever Bro's
|
||||
protocol analysis encounters a situation it would not expect
|
||||
(e.g., an RFC violation) it logs it in this file. Note that in
|
||||
practice, real-world networks tend to exhibit a large number of
|
||||
such "crud" that is usually not worth following up on.
|
||||
|
||||
As you can see, some log files are specific to a particular protocol,
|
||||
while others aggregate information across different types of activity.
|
||||
For a complete list of log files and a description of its purpose,
|
||||
see :doc:`Log Files </script-reference/log-files>`.
|
||||
|
||||
.. _bro-cut:
|
||||
|
||||
Using ``bro-cut``
|
||||
-----------------
|
||||
|
||||
The ``bro-cut`` utility can be used in place of other tools to build
|
||||
terminal commands that remain flexible and accurate independent of
|
||||
possible changes to the log file itself. It accomplishes this by parsing
|
||||
the header in each file and allowing the user to refer to the specific
|
||||
columnar data available (in contrast to tools like ``awk`` that
|
||||
require the user to refer to fields referenced by their position).
|
||||
For example, the following command extracts just the given columns
|
||||
from a ``conn.log``:
|
||||
|
||||
.. sourcecode:: console
|
||||
|
||||
$ cat conn.log | bro-cut id.orig_h id.orig_p id.resp_h duration
|
||||
141.142.220.202 5353 224.0.0.251 -
|
||||
fe80::217:f2ff:fed7:cf65 5353 ff02::fb -
|
||||
141.142.220.50 5353 224.0.0.251 -
|
||||
141.142.220.118 43927 141.142.2.2 0.000435
|
||||
141.142.220.118 37676 141.142.2.2 0.000420
|
||||
141.142.220.118 40526 141.142.2.2 0.000392
|
||||
141.142.220.118 32902 141.142.2.2 0.000317
|
||||
141.142.220.118 59816 141.142.2.2 0.000343
|
||||
141.142.220.118 59714 141.142.2.2 0.000375
|
||||
141.142.220.118 58206 141.142.2.2 0.000339
|
||||
[...]
|
||||
|
||||
The corresponding ``awk`` command will look like this:
|
||||
|
||||
.. sourcecode:: console
|
||||
|
||||
$ awk '/^[^#]/ {print $3, $4, $5, $6, $9}' conn.log
|
||||
141.142.220.202 5353 224.0.0.251 5353 -
|
||||
fe80::217:f2ff:fed7:cf65 5353 ff02::fb 5353 -
|
||||
141.142.220.50 5353 224.0.0.251 5353 -
|
||||
141.142.220.118 43927 141.142.2.2 53 0.000435
|
||||
141.142.220.118 37676 141.142.2.2 53 0.000420
|
||||
141.142.220.118 40526 141.142.2.2 53 0.000392
|
||||
141.142.220.118 32902 141.142.2.2 53 0.000317
|
||||
141.142.220.118 59816 141.142.2.2 53 0.000343
|
||||
141.142.220.118 59714 141.142.2.2 53 0.000375
|
||||
141.142.220.118 58206 141.142.2.2 53 0.000339
|
||||
[...]
|
||||
|
||||
While the output is similar, the advantages to using bro-cut over
|
||||
``awk`` lay in that, while ``awk`` is flexible and powerful, ``bro-cut``
|
||||
was specifically designed to work with Bro's log files. Firstly, the
|
||||
``bro-cut`` output includes only the log file entries, while the
|
||||
``awk`` solution needs to skip the header manually. Secondly, since
|
||||
``bro-cut`` uses the field descriptors to identify and extract data,
|
||||
it allows for flexibility independent of the format and contents of
|
||||
the log file. It's not uncommon for a Bro configuration to add extra
|
||||
fields to various log files as required by the environment. In this
|
||||
case, the fields in the ``awk`` command would have to be altered to
|
||||
compensate for the new position whereas the ``bro-cut`` output would
|
||||
not change.
|
||||
|
||||
.. note::
|
||||
|
||||
The sequence of field names given to ``bro-cut`` determines the
|
||||
output order, which means you can also use ``bro-cut`` to reorder
|
||||
fields. That can be helpful when piping into, e.g., ``sort``.
|
||||
|
||||
As you may have noticed, the command for ``bro-cut`` uses the output
|
||||
redirection through the ``cat`` command and ``|`` operator. Whereas
|
||||
tools like ``awk`` allow you to indicate the log file as a command
|
||||
line option, bro-cut only takes input through redirection such as
|
||||
``|`` and ``<``. There are a couple of ways to direct log file data
|
||||
into ``bro-cut``, each dependent upon the type of log file you're
|
||||
processing. A caveat of its use, however, is that all of the
|
||||
header lines must be present.
|
||||
|
||||
.. note::
|
||||
|
||||
``bro-cut`` provides an option ``-c`` to include a corresponding
|
||||
format header into the output, which allows to chain multiple
|
||||
``bro-cut`` instances or perform further post-processing that
|
||||
evaluates the header information.
|
||||
|
||||
In its default setup, Bro will rotate log files on an hourly basis,
|
||||
moving the current log file into a directory with format
|
||||
``YYYY-MM-DD`` and gzip compressing the file with a file format that
|
||||
includes the log file type and time range of the file. In the case of
|
||||
processing a compressed log file you simply adjust your command line
|
||||
tools to use the complementary ``z*`` versions of commands such as ``cat``
|
||||
(``zcat``) or ``grep`` (``zgrep``).
|
||||
|
||||
Working with Timestamps
|
||||
-----------------------
|
||||
|
||||
``bro-cut`` accepts the flag ``-d`` to convert the epoch time values
|
||||
in the log files to human-readable format. The following command
|
||||
includes the human readable time stamp, the unique identifier, the
|
||||
HTTP ``Host``, and HTTP ``URI`` as extracted from the ``http.log``
|
||||
file:
|
||||
|
||||
.. sourcecode:: console
|
||||
|
||||
$ bro-cut -d ts uid host uri < http.log
|
||||
2011-03-18T19:06:08+0000 CUM0KZ3MLUfNB0cl11 bits.wikimedia.org /skins-1.5/monobook/main.css
|
||||
2011-03-18T19:06:08+0000 CwjjYJ2WqgTbAqiHl6 upload.wikimedia.org /wikipedia/commons/6/63/Wikipedia-logo.png
|
||||
2011-03-18T19:06:08+0000 C3eiCBGOLw3VtHfOj upload.wikimedia.org /wikipedia/commons/thumb/b/bb/Wikipedia_wordmark.svg/174px-Wikipedia_wordmark.svg.png
|
||||
2011-03-18T19:06:08+0000 Ck51lg1bScffFj34Ri upload.wikimedia.org /wikipedia/commons/b/bd/Bookshelf-40x201_6.png
|
||||
2011-03-18T19:06:08+0000 CtxTCR2Yer0FR1tIBg upload.wikimedia.org /wikipedia/commons/thumb/8/8a/Wikinews-logo.png/35px-Wikinews-logo.png
|
||||
[...]
|
||||
|
||||
Often times log files from multiple sources are stored in UTC time to
|
||||
allow easy correlation. Converting the timestamp from a log file to
|
||||
UTC can be accomplished with the ``-u`` option:
|
||||
|
||||
.. sourcecode:: console
|
||||
|
||||
$ bro-cut -u ts uid host uri < http.log
|
||||
2011-03-18T19:06:08+0000 CUM0KZ3MLUfNB0cl11 bits.wikimedia.org /skins-1.5/monobook/main.css
|
||||
2011-03-18T19:06:08+0000 CwjjYJ2WqgTbAqiHl6 upload.wikimedia.org /wikipedia/commons/6/63/Wikipedia-logo.png
|
||||
2011-03-18T19:06:08+0000 C3eiCBGOLw3VtHfOj upload.wikimedia.org /wikipedia/commons/thumb/b/bb/Wikipedia_wordmark.svg/174px-Wikipedia_wordmark.svg.png
|
||||
2011-03-18T19:06:08+0000 Ck51lg1bScffFj34Ri upload.wikimedia.org /wikipedia/commons/b/bd/Bookshelf-40x201_6.png
|
||||
2011-03-18T19:06:08+0000 CtxTCR2Yer0FR1tIBg upload.wikimedia.org /wikipedia/commons/thumb/8/8a/Wikinews-logo.png/35px-Wikinews-logo.png
|
||||
[...]
|
||||
|
||||
The default time format when using the ``-d`` or ``-u`` is the
|
||||
``strftime`` format string ``%Y-%m-%dT%H:%M:%S%z`` which results in a
|
||||
string with year, month, day of month, followed by hour, minutes,
|
||||
seconds and the timezone offset. The default format can be altered by
|
||||
using the ``-D`` and ``-U`` flags, using the standard ``strftime``
|
||||
syntax. For example, to format the timestamp in the US-typical "Middle
|
||||
Endian" you could use a format string of: ``%d-%m-%YT%H:%M:%S%z``
|
||||
|
||||
.. sourcecode:: console
|
||||
|
||||
$ bro-cut -D %d-%m-%YT%H:%M:%S%z ts uid host uri < http.log
|
||||
18-03-2011T19:06:08+0000 CUM0KZ3MLUfNB0cl11 bits.wikimedia.org /skins-1.5/monobook/main.css
|
||||
18-03-2011T19:06:08+0000 CwjjYJ2WqgTbAqiHl6 upload.wikimedia.org /wikipedia/commons/6/63/Wikipedia-logo.png
|
||||
18-03-2011T19:06:08+0000 C3eiCBGOLw3VtHfOj upload.wikimedia.org /wikipedia/commons/thumb/b/bb/Wikipedia_wordmark.svg/174px-Wikipedia_wordmark.svg.png
|
||||
18-03-2011T19:06:08+0000 Ck51lg1bScffFj34Ri upload.wikimedia.org /wikipedia/commons/b/bd/Bookshelf-40x201_6.png
|
||||
18-03-2011T19:06:08+0000 CtxTCR2Yer0FR1tIBg upload.wikimedia.org /wikipedia/commons/thumb/8/8a/Wikinews-logo.png/35px-Wikinews-logo.png
|
||||
[...]
|
||||
|
||||
See ``man strfime`` for more options for the format string.
|
||||
|
||||
Using UIDs
|
||||
----------
|
||||
|
||||
While Bro can do signature-based analysis, its primary focus is on
|
||||
behavioral detection which alters the practice of log review from
|
||||
"reactionary review" to a process a little more akin to a hunting
|
||||
trip. A common progression of review includes correlating a session
|
||||
across multiple log files. As a connection is processed by Bro, a
|
||||
unique identifier is assigned to each session. This unique identifier
|
||||
is generally included in any log file entry associated with that
|
||||
connection and can be used to cross-reference different log files.
|
||||
|
||||
A simple example would be to cross-reference a UID seen in a
|
||||
``conn.log`` file. Here, we're looking for the connection with the
|
||||
largest number of bytes from the responder by redirecting the output
|
||||
for ``cat conn.log`` into bro-cut to extract the UID and the
|
||||
resp_bytes, then sorting that output by the resp_bytes field.
|
||||
|
||||
.. sourcecode:: console
|
||||
|
||||
$ cat conn.log | bro-cut uid resp_bytes | sort -nrk2 | head -5
|
||||
CwjjYJ2WqgTbAqiHl6 734
|
||||
CtxTCR2Yer0FR1tIBg 734
|
||||
Ck51lg1bScffFj34Ri 734
|
||||
CLNN1k2QMum1aexUK7 734
|
||||
CykQaM33ztNt0csB9a 733
|
||||
|
||||
Taking the UID of the first of the top responses, we can now
|
||||
crossreference that with the UIDs in the ``http.log`` file.
|
||||
|
||||
.. sourcecode:: console
|
||||
|
||||
$ cat http.log | bro-cut uid id.resp_h method status_code host uri | grep UM0KZ3MLUfNB0cl11
|
||||
CUM0KZ3MLUfNB0cl11 208.80.152.118 GET 304 bits.wikimedia.org /skins-1.5/monobook/main.css
|
||||
|
||||
As you can see there are two HTTP ``GET`` requests within the
|
||||
session that Bro identified and logged. Given that HTTP is a stream
|
||||
protocol, it can have multiple ``GET``/``POST``/etc requests in a
|
||||
stream and Bro is able to extract and track that information for you,
|
||||
giving you an in-depth and structured view into HTTP traffic on your
|
||||
network.
|
108
doc/examples/mimestats/index.rst
Normal file
108
doc/examples/mimestats/index.rst
Normal file
|
@ -0,0 +1,108 @@
|
|||
|
||||
.. _mime-stats:
|
||||
|
||||
====================
|
||||
MIME Type Statistics
|
||||
====================
|
||||
|
||||
Files are constantly transmitted over HTTP on regular networks. These
|
||||
files belong to a specific category (e.g., executable, text, image)
|
||||
identified by a `Multipurpose Internet Mail Extension (MIME)
|
||||
<http://en.wikipedia.org/wiki/MIME>`_. Although MIME was originally
|
||||
developed to identify the type of non-text attachments on email, it is
|
||||
also used by a web browser to identify the type of files transmitted and
|
||||
present them accordingly.
|
||||
|
||||
In this tutorial, we will demonstrate how to use the Sumstats Framework
|
||||
to collect statistical information based on MIME types; specifically,
|
||||
the total number of occurrences, size in bytes, and number of unique
|
||||
hosts transmitting files over HTTP per each type. For instructions on
|
||||
extracting and creating a local copy of these files, visit :ref:`this
|
||||
tutorial <http-monitor>`.
|
||||
|
||||
------------------------------------------------
|
||||
MIME Statistics with Sumstats
|
||||
------------------------------------------------
|
||||
|
||||
When working with the :ref:`Summary Statistics Framework
|
||||
<sumstats-framework>`, you need to define three different pieces: (i)
|
||||
Observations, where the event is observed and fed into the framework.
|
||||
(ii) Reducers, where observations are collected and measured. (iii)
|
||||
Sumstats, where the main functionality is implemented.
|
||||
|
||||
We start by defining our observation along with a record to store
|
||||
all statistical values and an observation interval. We are conducting our
|
||||
observation on the :bro:see:`HTTP::log_http` event and are interested
|
||||
in the MIME type, size of the file ("response_body_len"), and the
|
||||
originator host ("orig_h"). We use the MIME type as our key and create
|
||||
observers for the other two values.
|
||||
|
||||
.. literalinclude:: mimestats.bro
|
||||
:caption:
|
||||
:language: bro
|
||||
:linenos:
|
||||
:lines: 6-29
|
||||
:lineno-start: 6
|
||||
|
||||
.. literalinclude:: mimestats.bro
|
||||
:caption:
|
||||
:language: bro
|
||||
:linenos:
|
||||
:lines: 54-64
|
||||
:lineno-start: 54
|
||||
|
||||
Next, we create the reducers. The first will accumulate file sizes
|
||||
and the second will make sure we only store a host ID once. Below is
|
||||
the partial code from a :bro:see:`bro_init` handler.
|
||||
|
||||
.. literalinclude:: mimestats.bro
|
||||
:caption:
|
||||
:language: bro
|
||||
:linenos:
|
||||
:lines: 34-37
|
||||
:lineno-start: 34
|
||||
|
||||
In our final step, we create the SumStats where we check for the
|
||||
observation interval. Once it expires, we populate the record
|
||||
(defined above) with all the relevant data and write it to a log.
|
||||
|
||||
.. literalinclude:: mimestats.bro
|
||||
:caption:
|
||||
:language: bro
|
||||
:linenos:
|
||||
:lines: 38-51
|
||||
:lineno-start: 38
|
||||
|
||||
After putting the three pieces together we end up with the following
|
||||
final code for our script.
|
||||
|
||||
.. literalinclude:: mimestats.bro
|
||||
:caption:
|
||||
:language: bro
|
||||
:linenos:
|
||||
|
||||
.. sourcecode:: console
|
||||
|
||||
$ bro -r http/bro.org.pcap mimestats.bro
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path mime_metrics
|
||||
#open 2018-12-14-16-25-06
|
||||
#fields ts ts_delta mtype uniq_hosts hits bytes
|
||||
#types time interval string count count count
|
||||
1389719059.311698 300.000000 image/png 1 9 82176
|
||||
1389719059.311698 300.000000 image/gif 1 1 172
|
||||
1389719059.311698 300.000000 image/x-icon 1 2 2300
|
||||
1389719059.311698 300.000000 text/html 1 2 42231
|
||||
1389719059.311698 300.000000 text/plain 1 15 128001
|
||||
1389719059.311698 300.000000 image/jpeg 1 1 186859
|
||||
1389719059.311698 300.000000 application/pgp-signature 1 1 836
|
||||
#close 2018-12-14-16-25-06
|
||||
|
||||
.. note::
|
||||
|
||||
The redefinition of :bro:see:`Site::local_nets` is only done inside
|
||||
this script to make it a self-contained example. It's typically
|
||||
redefined somewhere else.
|
64
doc/examples/mimestats/mimestats.bro
Normal file
64
doc/examples/mimestats/mimestats.bro
Normal file
|
@ -0,0 +1,64 @@
|
|||
@load base/utils/site
|
||||
@load base/frameworks/sumstats
|
||||
|
||||
redef Site::local_nets += { 10.0.0.0/8 };
|
||||
|
||||
module MimeMetrics;
|
||||
|
||||
export {
|
||||
|
||||
redef enum Log::ID += { LOG };
|
||||
|
||||
type Info: record {
|
||||
## Timestamp when the log line was finished and written.
|
||||
ts: time &log;
|
||||
## Time interval that the log line covers.
|
||||
ts_delta: interval &log;
|
||||
## The mime type
|
||||
mtype: string &log;
|
||||
## The number of unique local hosts that fetched this mime type
|
||||
uniq_hosts: count &log;
|
||||
## The number of hits to the mime type
|
||||
hits: count &log;
|
||||
## The total number of bytes received by this mime type
|
||||
bytes: count &log;
|
||||
};
|
||||
|
||||
## The frequency of logging the stats collected by this script.
|
||||
const break_interval = 5mins &redef;
|
||||
}
|
||||
|
||||
event bro_init() &priority=3
|
||||
{
|
||||
Log::create_stream(MimeMetrics::LOG, [$columns=Info, $path="mime_metrics"]);
|
||||
local r1: SumStats::Reducer = [$stream="mime.bytes",
|
||||
$apply=set(SumStats::SUM)];
|
||||
local r2: SumStats::Reducer = [$stream="mime.hits",
|
||||
$apply=set(SumStats::UNIQUE)];
|
||||
SumStats::create([$name="mime-metrics",
|
||||
$epoch=break_interval,
|
||||
$reducers=set(r1, r2),
|
||||
$epoch_result(ts: time, key: SumStats::Key, result: SumStats::Result) =
|
||||
{
|
||||
local l: Info;
|
||||
l$ts = network_time();
|
||||
l$ts_delta = break_interval;
|
||||
l$mtype = key$str;
|
||||
l$bytes = double_to_count(floor(result["mime.bytes"]$sum));
|
||||
l$hits = result["mime.hits"]$num;
|
||||
l$uniq_hosts = result["mime.hits"]$unique;
|
||||
Log::write(MimeMetrics::LOG, l);
|
||||
}]);
|
||||
}
|
||||
|
||||
event HTTP::log_http(rec: HTTP::Info)
|
||||
{
|
||||
if ( Site::is_local_addr(rec$id$orig_h) && rec?$resp_mime_types )
|
||||
{
|
||||
local mime_type = rec$resp_mime_types[0];
|
||||
SumStats::observe("mime.bytes", [$str=mime_type],
|
||||
[$num=rec$response_body_len]);
|
||||
SumStats::observe("mime.hits", [$str=mime_type],
|
||||
[$str=cat(rec$id$orig_h)]);
|
||||
}
|
||||
}
|
6
doc/examples/scripting/connection_record_01.bro
Normal file
6
doc/examples/scripting/connection_record_01.bro
Normal file
|
@ -0,0 +1,6 @@
|
|||
@load base/protocols/conn
|
||||
|
||||
event connection_state_remove(c: connection)
|
||||
{
|
||||
print c;
|
||||
}
|
7
doc/examples/scripting/connection_record_02.bro
Normal file
7
doc/examples/scripting/connection_record_02.bro
Normal file
|
@ -0,0 +1,7 @@
|
|||
@load base/protocols/conn
|
||||
@load base/protocols/http
|
||||
|
||||
event connection_state_remove(c: connection)
|
||||
{
|
||||
print c;
|
||||
}
|
22
doc/examples/scripting/data_struct_record_01.bro
Normal file
22
doc/examples/scripting/data_struct_record_01.bro
Normal file
|
@ -0,0 +1,22 @@
|
|||
type Service: record {
|
||||
name: string;
|
||||
ports: set[port];
|
||||
rfc: count;
|
||||
};
|
||||
|
||||
function print_service(serv: Service)
|
||||
{
|
||||
print fmt("Service: %s(RFC%d)",serv$name, serv$rfc);
|
||||
|
||||
for ( p in serv$ports )
|
||||
print fmt(" port: %s", p);
|
||||
}
|
||||
|
||||
event bro_init()
|
||||
{
|
||||
local dns: Service = [$name="dns", $ports=set(53/udp, 53/tcp), $rfc=1035];
|
||||
local http: Service = [$name="http", $ports=set(80/tcp, 8080/tcp), $rfc=2616];
|
||||
|
||||
print_service(dns);
|
||||
print_service(http);
|
||||
}
|
41
doc/examples/scripting/data_struct_record_02.bro
Normal file
41
doc/examples/scripting/data_struct_record_02.bro
Normal file
|
@ -0,0 +1,41 @@
|
|||
type Service: record {
|
||||
name: string;
|
||||
ports: set[port];
|
||||
rfc: count;
|
||||
};
|
||||
|
||||
type System: record {
|
||||
name: string;
|
||||
services: set[Service];
|
||||
};
|
||||
|
||||
function print_service(serv: Service)
|
||||
{
|
||||
print fmt(" Service: %s(RFC%d)",serv$name, serv$rfc);
|
||||
|
||||
for ( p in serv$ports )
|
||||
print fmt(" port: %s", p);
|
||||
}
|
||||
|
||||
function print_system(sys: System)
|
||||
{
|
||||
print fmt("System: %s", sys$name);
|
||||
|
||||
for ( s in sys$services )
|
||||
print_service(s);
|
||||
}
|
||||
|
||||
event bro_init()
|
||||
{
|
||||
local server01: System;
|
||||
server01$name = "morlock";
|
||||
add server01$services[[ $name="dns", $ports=set(53/udp, 53/tcp), $rfc=1035]];
|
||||
add server01$services[[ $name="http", $ports=set(80/tcp, 8080/tcp), $rfc=2616]];
|
||||
print_system(server01);
|
||||
|
||||
|
||||
# local dns: Service = [ $name="dns", $ports=set(53/udp, 53/tcp), $rfc=1035];
|
||||
# local http: Service = [ $name="http", $ports=set(80/tcp, 8080/tcp), $rfc=2616];
|
||||
# print_service(dns);
|
||||
# print_service(http);
|
||||
}
|
22
doc/examples/scripting/data_struct_set_declaration.bro
Normal file
22
doc/examples/scripting/data_struct_set_declaration.bro
Normal file
|
@ -0,0 +1,22 @@
|
|||
event bro_init()
|
||||
{
|
||||
local ssl_ports: set[port];
|
||||
local non_ssl_ports = set( 23/tcp, 80/tcp, 143/tcp, 25/tcp );
|
||||
|
||||
# SSH
|
||||
add ssl_ports[22/tcp];
|
||||
# HTTPS
|
||||
add ssl_ports[443/tcp];
|
||||
# IMAPS
|
||||
add ssl_ports[993/tcp];
|
||||
|
||||
# Check for SMTPS
|
||||
if ( 587/tcp !in ssl_ports )
|
||||
add ssl_ports[587/tcp];
|
||||
|
||||
for ( i in ssl_ports )
|
||||
print fmt("SSL Port: %s", i);
|
||||
|
||||
for ( i in non_ssl_ports )
|
||||
print fmt("Non-SSL Port: %s", i);
|
||||
}
|
13
doc/examples/scripting/data_struct_table_complex.bro
Normal file
13
doc/examples/scripting/data_struct_table_complex.bro
Normal file
|
@ -0,0 +1,13 @@
|
|||
event bro_init()
|
||||
{
|
||||
local samurai_flicks: table[string, string, count, string] of string;
|
||||
|
||||
samurai_flicks["Kihachi Okamoto", "Toho", 1968, "Tatsuya Nakadai"] = "Kiru";
|
||||
samurai_flicks["Hideo Gosha", "Fuji", 1969, "Tatsuya Nakadai"] = "Goyokin";
|
||||
samurai_flicks["Masaki Kobayashi", "Shochiku Eiga", 1962, "Tatsuya Nakadai" ] = "Harakiri";
|
||||
samurai_flicks["Yoji Yamada", "Eisei Gekijo", 2002, "Hiroyuki Sanada" ] = "Tasogare Seibei";
|
||||
|
||||
for ( [d, s, y, a] in samurai_flicks )
|
||||
print fmt("%s was released in %d by %s studios, directed by %s and starring %s", samurai_flicks[d, s, y, a], y, s, d, a);
|
||||
}
|
||||
|
19
doc/examples/scripting/data_struct_table_declaration.bro
Normal file
19
doc/examples/scripting/data_struct_table_declaration.bro
Normal file
|
@ -0,0 +1,19 @@
|
|||
event bro_init()
|
||||
{
|
||||
# Declaration of the table.
|
||||
local ssl_services: table[string] of port;
|
||||
|
||||
# Initialize the table.
|
||||
ssl_services = table(["SSH"] = 22/tcp, ["HTTPS"] = 443/tcp);
|
||||
|
||||
# Insert one key-yield pair into the table.
|
||||
ssl_services["IMAPS"] = 993/tcp;
|
||||
|
||||
# Check if the key "SMTPS" is not in the table.
|
||||
if ( "SMTPS" !in ssl_services )
|
||||
ssl_services["SMTPS"] = 587/tcp;
|
||||
|
||||
# Iterate over each key in the table.
|
||||
for ( k in ssl_services )
|
||||
print fmt("Service Name: %s - Common Port: %s", k, ssl_services[k]);
|
||||
}
|
7
doc/examples/scripting/data_struct_vector.bro
Normal file
7
doc/examples/scripting/data_struct_vector.bro
Normal file
|
@ -0,0 +1,7 @@
|
|||
event bro_init()
|
||||
{
|
||||
local v: vector of count = vector(1, 2, 3, 4);
|
||||
local w = vector(1, 2, 3, 4);
|
||||
print v;
|
||||
print w;
|
||||
}
|
15
doc/examples/scripting/data_struct_vector_declaration.bro
Normal file
15
doc/examples/scripting/data_struct_vector_declaration.bro
Normal file
|
@ -0,0 +1,15 @@
|
|||
event bro_init()
|
||||
{
|
||||
local v1: vector of count;
|
||||
local v2 = vector(1, 2, 3, 4);
|
||||
|
||||
v1 += 1;
|
||||
v1 += 2;
|
||||
v1 += 3;
|
||||
v1 += 4;
|
||||
|
||||
print fmt("contents of v1: %s", v1);
|
||||
print fmt("length of v1: %d", |v1|);
|
||||
print fmt("contents of v2: %s", v2);
|
||||
print fmt("length of v2: %d", |v2|);
|
||||
}
|
7
doc/examples/scripting/data_struct_vector_iter.bro
Normal file
7
doc/examples/scripting/data_struct_vector_iter.bro
Normal file
|
@ -0,0 +1,7 @@
|
|||
event bro_init()
|
||||
{
|
||||
local addr_vector: vector of addr = vector(1.2.3.4, 2.3.4.5, 3.4.5.6);
|
||||
|
||||
for (i in addr_vector)
|
||||
print mask_addr(addr_vector[i], 18);
|
||||
}
|
9
doc/examples/scripting/data_type_const.bro
Normal file
9
doc/examples/scripting/data_type_const.bro
Normal file
|
@ -0,0 +1,9 @@
|
|||
const port_list: table[port] of string &redef;
|
||||
|
||||
redef port_list += { [6666/tcp] = "IRC"};
|
||||
redef port_list += { [80/tcp] = "WWW" };
|
||||
|
||||
event bro_init()
|
||||
{
|
||||
print port_list;
|
||||
}
|
4
doc/examples/scripting/data_type_const_simple.bro
Normal file
4
doc/examples/scripting/data_type_const_simple.bro
Normal file
|
@ -0,0 +1,4 @@
|
|||
@load base/protocols/http
|
||||
|
||||
redef HTTP::default_capture_password = T;
|
||||
|
9
doc/examples/scripting/data_type_declaration.bro
Normal file
9
doc/examples/scripting/data_type_declaration.bro
Normal file
|
@ -0,0 +1,9 @@
|
|||
event bro_init()
|
||||
{
|
||||
local a: int;
|
||||
a = 10;
|
||||
local b = 10;
|
||||
|
||||
if ( a == b )
|
||||
print fmt("A: %d, B: %d", a, b);
|
||||
}
|
18
doc/examples/scripting/data_type_interval.bro
Normal file
18
doc/examples/scripting/data_type_interval.bro
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Store the time the previous connection was established.
|
||||
global last_connection_time: time;
|
||||
|
||||
# boolean value to indicate whether we have seen a previous connection.
|
||||
global connection_seen: bool = F;
|
||||
|
||||
event connection_established(c: connection)
|
||||
{
|
||||
local net_time: time = network_time();
|
||||
|
||||
print fmt("%s: New connection established from %s to %s", strftime("%Y/%M/%d %H:%m:%S", net_time), c$id$orig_h, c$id$resp_h);
|
||||
|
||||
if ( connection_seen )
|
||||
print fmt(" Time since last connection: %s", net_time - last_connection_time);
|
||||
|
||||
last_connection_time = net_time;
|
||||
connection_seen = T;
|
||||
}
|
11
doc/examples/scripting/data_type_local.bro
Normal file
11
doc/examples/scripting/data_type_local.bro
Normal file
|
@ -0,0 +1,11 @@
|
|||
function add_two(i: count): count
|
||||
{
|
||||
local added_two = i+2;
|
||||
print fmt("i + 2 = %d", added_two);
|
||||
return added_two;
|
||||
}
|
||||
|
||||
event bro_init()
|
||||
{
|
||||
local test = add_two(10);
|
||||
}
|
13
doc/examples/scripting/data_type_pattern_01.bro
Normal file
13
doc/examples/scripting/data_type_pattern_01.bro
Normal file
|
@ -0,0 +1,13 @@
|
|||
event bro_init()
|
||||
{
|
||||
local test_string = "The quick brown fox jumps over the lazy dog.";
|
||||
local test_pattern = /quick|lazy/;
|
||||
|
||||
if ( test_pattern in test_string )
|
||||
{
|
||||
local results = split(test_string, test_pattern);
|
||||
print results[1];
|
||||
print results[2];
|
||||
print results[3];
|
||||
}
|
||||
}
|
10
doc/examples/scripting/data_type_pattern_02.bro
Normal file
10
doc/examples/scripting/data_type_pattern_02.bro
Normal file
|
@ -0,0 +1,10 @@
|
|||
event bro_init()
|
||||
{
|
||||
local test_string = "equality";
|
||||
|
||||
local test_pattern = /equal/;
|
||||
print fmt("%s and %s %s equal", test_string, test_pattern, test_pattern == test_string ? "are" : "are not");
|
||||
|
||||
test_pattern = /equality/;
|
||||
print fmt("%s and %s %s equal", test_string, test_pattern, test_pattern == test_string ? "are" : "are not");
|
||||
}
|
25
doc/examples/scripting/data_type_record.bro
Normal file
25
doc/examples/scripting/data_type_record.bro
Normal file
|
@ -0,0 +1,25 @@
|
|||
module Conn;
|
||||
|
||||
export {
|
||||
## The record type which contains column fields of the connection log.
|
||||
type Info: record {
|
||||
ts: time &log;
|
||||
uid: string &log;
|
||||
id: conn_id &log;
|
||||
proto: transport_proto &log;
|
||||
service: string &log &optional;
|
||||
duration: interval &log &optional;
|
||||
orig_bytes: count &log &optional;
|
||||
resp_bytes: count &log &optional;
|
||||
conn_state: string &log &optional;
|
||||
local_orig: bool &log &optional;
|
||||
local_resp: bool &log &optional;
|
||||
missed_bytes: count &log &default=0;
|
||||
history: string &log &optional;
|
||||
orig_pkts: count &log &optional;
|
||||
orig_ip_bytes: count &log &optional;
|
||||
resp_pkts: count &log &optional;
|
||||
resp_ip_bytes: count &log &optional;
|
||||
tunnel_parents: set[string] &log;
|
||||
};
|
||||
}
|
15
doc/examples/scripting/data_type_subnets.bro
Normal file
15
doc/examples/scripting/data_type_subnets.bro
Normal file
|
@ -0,0 +1,15 @@
|
|||
event bro_init()
|
||||
{
|
||||
local subnets = vector(172.16.0.0/20, 172.16.16.0/20, 172.16.32.0/20, 172.16.48.0/20);
|
||||
local addresses = vector(172.16.4.56, 172.16.47.254, 172.16.22.45, 172.16.1.1);
|
||||
|
||||
for ( a in addresses )
|
||||
{
|
||||
for ( s in subnets )
|
||||
{
|
||||
if ( addresses[a] in subnets[s] )
|
||||
print fmt("%s belongs to subnet %s", addresses[a], subnets[s]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
4
doc/examples/scripting/data_type_time.bro
Normal file
4
doc/examples/scripting/data_type_time.bro
Normal file
|
@ -0,0 +1,4 @@
|
|||
event connection_established(c: connection)
|
||||
{
|
||||
print fmt("%s: New connection established from %s to %s\n", strftime("%Y/%M/%d %H:%m:%S", network_time()), c$id$orig_h, c$id$resp_h);
|
||||
}
|
19
doc/examples/scripting/framework_logging_factorial_01.bro
Normal file
19
doc/examples/scripting/framework_logging_factorial_01.bro
Normal file
|
@ -0,0 +1,19 @@
|
|||
module Factor;
|
||||
|
||||
function factorial(n: count): count
|
||||
{
|
||||
if ( n == 0 )
|
||||
return 1;
|
||||
else
|
||||
return ( n * factorial(n - 1) );
|
||||
}
|
||||
|
||||
event bro_init()
|
||||
{
|
||||
local numbers: vector of count = vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
|
||||
|
||||
for ( n in numbers )
|
||||
print fmt("%d", factorial(numbers[n]));
|
||||
}
|
||||
|
||||
|
35
doc/examples/scripting/framework_logging_factorial_02.bro
Normal file
35
doc/examples/scripting/framework_logging_factorial_02.bro
Normal file
|
@ -0,0 +1,35 @@
|
|||
module Factor;
|
||||
|
||||
export {
|
||||
# Append the value LOG to the Log::ID enumerable.
|
||||
redef enum Log::ID += { LOG };
|
||||
|
||||
# Define a new type called Factor::Info.
|
||||
type Info: record {
|
||||
num: count &log;
|
||||
factorial_num: count &log;
|
||||
};
|
||||
}
|
||||
|
||||
function factorial(n: count): count
|
||||
{
|
||||
if ( n == 0 )
|
||||
return 1;
|
||||
|
||||
else
|
||||
return ( n * factorial(n - 1) );
|
||||
}
|
||||
|
||||
event bro_init()
|
||||
{
|
||||
# Create the logging stream.
|
||||
Log::create_stream(LOG, [$columns=Info, $path="factor"]);
|
||||
}
|
||||
|
||||
event bro_done()
|
||||
{
|
||||
local numbers: vector of count = vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
|
||||
for ( n in numbers )
|
||||
Log::write( Factor::LOG, [$num=numbers[n],
|
||||
$factorial_num=factorial(numbers[n])]);
|
||||
}
|
45
doc/examples/scripting/framework_logging_factorial_03.bro
Normal file
45
doc/examples/scripting/framework_logging_factorial_03.bro
Normal file
|
@ -0,0 +1,45 @@
|
|||
module Factor;
|
||||
|
||||
export {
|
||||
redef enum Log::ID += { LOG };
|
||||
|
||||
type Info: record {
|
||||
num: count &log;
|
||||
factorial_num: count &log;
|
||||
};
|
||||
}
|
||||
|
||||
function factorial(n: count): count
|
||||
{
|
||||
if ( n == 0 )
|
||||
return 1;
|
||||
|
||||
else
|
||||
return (n * factorial(n - 1));
|
||||
}
|
||||
|
||||
event bro_done()
|
||||
{
|
||||
local numbers: vector of count = vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
|
||||
for ( n in numbers )
|
||||
Log::write( Factor::LOG, [$num=numbers[n],
|
||||
$factorial_num=factorial(numbers[n])]);
|
||||
}
|
||||
|
||||
function mod5(id: Log::ID, path: string, rec: Factor::Info) : string
|
||||
{
|
||||
if ( rec$factorial_num % 5 == 0 )
|
||||
return "factor-mod5";
|
||||
|
||||
else
|
||||
return "factor-non5";
|
||||
}
|
||||
|
||||
event bro_init()
|
||||
{
|
||||
Log::create_stream(LOG, [$columns=Info, $path="factor"]);
|
||||
|
||||
local filter: Log::Filter = [$name="split-mod5s", $path_func=mod5];
|
||||
Log::add_filter(Factor::LOG, filter);
|
||||
Log::remove_filter(Factor::LOG, "default");
|
||||
}
|
50
doc/examples/scripting/framework_logging_factorial_04.bro
Normal file
50
doc/examples/scripting/framework_logging_factorial_04.bro
Normal file
|
@ -0,0 +1,50 @@
|
|||
module Factor;
|
||||
|
||||
export {
|
||||
redef enum Log::ID += { LOG };
|
||||
|
||||
type Info: record {
|
||||
num: count &log;
|
||||
factorial_num: count &log;
|
||||
};
|
||||
|
||||
global log_factor: event(rec: Info);
|
||||
}
|
||||
|
||||
function factorial(n: count): count
|
||||
{
|
||||
if ( n == 0 )
|
||||
return 1;
|
||||
|
||||
else
|
||||
return (n * factorial(n - 1));
|
||||
}
|
||||
|
||||
event bro_init()
|
||||
{
|
||||
Log::create_stream(LOG, [$columns=Info, $ev=log_factor, $path="factor"]);
|
||||
}
|
||||
|
||||
event bro_done()
|
||||
{
|
||||
local numbers: vector of count = vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
|
||||
for ( n in numbers )
|
||||
Log::write( Factor::LOG, [$num=numbers[n],
|
||||
$factorial_num=factorial(numbers[n])]);
|
||||
}
|
||||
|
||||
function mod5(id: Log::ID, path: string, rec: Factor::Info) : string
|
||||
{
|
||||
if ( rec$factorial_num % 5 == 0 )
|
||||
return "factor-mod5";
|
||||
|
||||
else
|
||||
return "factor-non5";
|
||||
}
|
||||
|
||||
event bro_init()
|
||||
{
|
||||
local filter: Log::Filter = [$name="split-mod5s", $path_func=mod5];
|
||||
Log::add_filter(Factor::LOG, filter);
|
||||
Log::remove_filter(Factor::LOG, "default");
|
||||
}
|
7
doc/examples/scripting/framework_notice_hook_01.bro
Normal file
7
doc/examples/scripting/framework_notice_hook_01.bro
Normal file
|
@ -0,0 +1,7 @@
|
|||
@load policy/protocols/ssh/interesting-hostnames.bro
|
||||
|
||||
hook Notice::policy(n: Notice::Info)
|
||||
{
|
||||
if ( n$note == SSH::Interesting_Hostname_Login )
|
||||
add n$actions[Notice::ACTION_EMAIL];
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
@load policy/protocols/ssl/expiring-certs.bro
|
||||
|
||||
hook Notice::policy(n: Notice::Info)
|
||||
{
|
||||
if ( n$note == SSL::Certificate_Expires_Soon )
|
||||
n$suppress_for = 12hrs;
|
||||
}
|
7
doc/examples/scripting/framework_notice_shortcuts_01.bro
Normal file
7
doc/examples/scripting/framework_notice_shortcuts_01.bro
Normal file
|
@ -0,0 +1,7 @@
|
|||
@load policy/protocols/ssh/interesting-hostnames.bro
|
||||
@load base/protocols/ssh/
|
||||
|
||||
redef Notice::emailed_types += {
|
||||
SSH::Interesting_Hostname_Login
|
||||
};
|
||||
|
6
doc/examples/scripting/framework_notice_shortcuts_02.bro
Normal file
6
doc/examples/scripting/framework_notice_shortcuts_02.bro
Normal file
|
@ -0,0 +1,6 @@
|
|||
@load policy/protocols/ssh/interesting-hostnames.bro
|
||||
@load base/protocols/ssh/
|
||||
|
||||
redef Notice::type_suppression_intervals += {
|
||||
[SSH::Interesting_Hostname_Login] = 1day,
|
||||
};
|
7
doc/examples/scripting/http_main.bro
Normal file
7
doc/examples/scripting/http_main.bro
Normal file
|
@ -0,0 +1,7 @@
|
|||
module HTTP;
|
||||
|
||||
export {
|
||||
## This setting changes if passwords used in Basic-Auth are captured or
|
||||
## not.
|
||||
const default_capture_password = F &redef;
|
||||
}
|
1706
doc/examples/scripting/index.rst
Normal file
1706
doc/examples/scripting/index.rst
Normal file
File diff suppressed because it is too large
Load diff
4
doc/examples/scripting/using_bro_sandbox_01
Normal file
4
doc/examples/scripting/using_bro_sandbox_01
Normal file
|
@ -0,0 +1,4 @@
|
|||
# @TEST-EXEC: bro -r ${TRACES}/wikipedia.trace
|
||||
# @TEST-EXEC: btest-diff conn.log
|
||||
# @TEST-EXEC: btest-diff http.log
|
||||
|
4
doc/examples/scripting/using_bro_sandbox_02
Normal file
4
doc/examples/scripting/using_bro_sandbox_02
Normal file
|
@ -0,0 +1,4 @@
|
|||
# @TEST-EXEC: bro -r ${TRACES}/workshop_2011_browse.trace
|
||||
# @TEST-EXEC: btest-diff conn.log
|
||||
# @TEST-EXEC: btest-diff http.log
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue