mirror of
https://github.com/zeek/zeek.git
synced 2025-10-04 23:58:20 +00:00
Add unit tests for new Bro Manual docs.
This commit is contained in:
parent
c5ab33d88f
commit
e18084b68d
52 changed files with 1196 additions and 374 deletions
|
@ -0,0 +1,14 @@
|
|||
.. rst-class:: btest-cmd
|
||||
|
||||
.. code-block:: none
|
||||
:linenos:
|
||||
:emphasize-lines: 1,1
|
||||
|
||||
# bro -r http/bro.org.pcap file_extraction.bro
|
||||
Extracting file HTTP-FiIpIB2hRQSDBOSJRg.html
|
||||
Extracting file HTTP-FnaT2a3UDd093opCB9.txt
|
||||
Extracting file HTTP-FsvATF146kf1Emc21j.txt
|
||||
Extracting file HTTP-FkMQHg2nBr44fc5h63.txt
|
||||
Extracting file HTTP-FfQGqj4Fhh3pH7nVQj.txt
|
||||
[...]
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
.. rst-class:: btest-cmd
|
||||
|
||||
.. code-block:: none
|
||||
:linenos:
|
||||
:emphasize-lines: 1,1
|
||||
|
||||
# bro -r ftp/bruteforce.pcap protocols/ftp/detect-bruteforcing.bro
|
||||
|
||||
.. rst-class:: btest-include
|
||||
|
||||
.. code-block:: guess
|
||||
:linenos:
|
||||
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path notice
|
||||
#open 2014-01-21-21-56-07
|
||||
#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 table[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 - - - bro Notice::ACTION_LOG 3600.000000 F - - - - -
|
||||
#close 2014-01-21-21-56-07
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
.. rst-class:: btest-cmd
|
||||
|
||||
.. code-block:: none
|
||||
:linenos:
|
||||
:emphasize-lines: 1,1
|
||||
|
||||
# bro -r http/proxy.pcap http_proxy_01.bro
|
||||
A local server is acting as an open proxy: 192.168.56.101
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
.. rst-class:: btest-cmd
|
||||
|
||||
.. code-block:: none
|
||||
:linenos:
|
||||
:emphasize-lines: 1,1
|
||||
|
||||
# bro -r http/proxy.pcap http_proxy_02.bro
|
||||
A local server is acting as an open proxy: 192.168.56.101
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
.. rst-class:: btest-cmd
|
||||
|
||||
.. code-block:: none
|
||||
:linenos:
|
||||
:emphasize-lines: 1,1
|
||||
|
||||
# bro -r http/proxy.pcap http_proxy_03.bro
|
||||
A local server is acting as an open proxy: 192.168.56.101
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
.. rst-class:: btest-cmd
|
||||
|
||||
.. code-block:: none
|
||||
:linenos:
|
||||
:emphasize-lines: 1,1
|
||||
|
||||
# bro -r http/proxy.pcap http_proxy_04.bro
|
||||
|
||||
.. rst-class:: btest-include
|
||||
|
||||
.. code-block:: guess
|
||||
:linenos:
|
||||
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path notice
|
||||
#open 2014-01-21-20-11-20
|
||||
#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 table[enum] interval bool string string string double double
|
||||
1389654450.449603 CXWv6p3arKYeMETxOg 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 - bro Notice::ACTION_LOG 86400.000000 F - - - - -
|
||||
#close 2014-01-21-20-11-20
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
file_extraction.bro
|
||||
|
||||
|
||||
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_new(f: fa_file)
|
||||
{
|
||||
if ( f$source != "HTTP" )
|
||||
return;
|
||||
|
||||
if ( ! f?$mime_type )
|
||||
return;
|
||||
|
||||
if ( f$mime_type !in mime_to_ext )
|
||||
return;
|
||||
|
||||
local fname = fmt("%s-%s.%s", f$source, f$id, mime_to_ext[f$mime_type]);
|
||||
print fmt("Extracting file %s", fname);
|
||||
Files::add_analyzer(f, Files::ANALYZER_EXTRACT, [$extract_filename=fname]);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
http_proxy_01.bro
|
||||
|
||||
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);
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
http_proxy_02.bro
|
||||
|
||||
|
||||
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);
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
http_proxy_03.bro
|
||||
|
||||
|
||||
@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);
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
http_proxy_04.bro
|
||||
|
||||
@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]);
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
mimestats.bro
|
||||
|
||||
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 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)]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
mimestats.bro
|
||||
|
||||
local r1: SumStats::Reducer = [$stream="mime.bytes",
|
||||
$apply=set(SumStats::SUM)];
|
||||
local r2: SumStats::Reducer = [$stream="mime.hits",
|
||||
$apply=set(SumStats::UNIQUE)];
|
|
@ -0,0 +1,18 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
mimestats.bro
|
||||
|
||||
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);
|
||||
}]);
|
|
@ -0,0 +1,68 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
mimestats.bro
|
||||
|
||||
@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]);
|
||||
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)]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
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)]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
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)]);
|
||||
}]);
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
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)]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
.. rst-class:: btest-cmd
|
||||
|
||||
.. code-block:: none
|
||||
:linenos:
|
||||
:emphasize-lines: 1,1
|
||||
|
||||
# bro -r http/bro.org.pcap mimestats.bro
|
||||
|
||||
.. rst-class:: btest-include
|
||||
|
||||
.. code-block:: guess
|
||||
:linenos:
|
||||
|
||||
#separator \x09
|
||||
#set_separator ,
|
||||
#empty_field (empty)
|
||||
#unset_field -
|
||||
#path mime_metrics
|
||||
#open 2014-01-21-21-35-28
|
||||
#fields ts ts_delta mtype uniq_hosts hits bytes
|
||||
#types time interval string count count count
|
||||
1389719059.311698 300.000000 text/html 1 4 53070
|
||||
1389719059.311698 300.000000 image/jpeg 1 1 186859
|
||||
1389719059.311698 300.000000 text/troff 1 1 2957
|
||||
1389719059.311698 300.000000 application/pgp-signature 1 1 836
|
||||
1389719059.311698 300.000000 text/plain 1 12 114205
|
||||
1389719059.311698 300.000000 image/gif 1 1 172
|
||||
1389719059.311698 300.000000 image/png 1 9 82176
|
||||
1389719059.311698 300.000000 image/x-icon 1 2 2300
|
||||
#close 2014-01-21-21-35-28
|
||||
|
BIN
testing/btest/Traces/ftp/bruteforce.pcap
Normal file
BIN
testing/btest/Traces/ftp/bruteforce.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/http/bro.org.pcap
Normal file
BIN
testing/btest/Traces/http/bro.org.pcap
Normal file
Binary file not shown.
BIN
testing/btest/Traces/http/proxy.pcap
Normal file
BIN
testing/btest/Traces/http/proxy.pcap
Normal file
Binary file not shown.
1
testing/btest/doc/sphinx/file_extraction.btest
Normal file
1
testing/btest/doc/sphinx/file_extraction.btest
Normal file
|
@ -0,0 +1 @@
|
|||
@TEST-EXEC: btest-rst-cmd -n 5 bro -r ${TRACES}/http/bro.org.pcap ${DOC_ROOT}/httpmonitor/file_extraction.bro
|
2
testing/btest/doc/sphinx/ftp-bruteforce.btest
Normal file
2
testing/btest/doc/sphinx/ftp-bruteforce.btest
Normal file
|
@ -0,0 +1,2 @@
|
|||
@TEST-EXEC: btest-rst-cmd bro -r ${TRACES}/ftp/bruteforce.pcap protocols/ftp/detect-bruteforcing.bro
|
||||
@TEST-EXEC: btest-rst-include notice.log
|
1
testing/btest/doc/sphinx/http_proxy_01.btest
Normal file
1
testing/btest/doc/sphinx/http_proxy_01.btest
Normal file
|
@ -0,0 +1 @@
|
|||
@TEST-EXEC: btest-rst-cmd bro -r ${TRACES}/http/proxy.pcap ${DOC_ROOT}/httpmonitor/http_proxy_01.bro
|
1
testing/btest/doc/sphinx/http_proxy_02.btest
Normal file
1
testing/btest/doc/sphinx/http_proxy_02.btest
Normal file
|
@ -0,0 +1 @@
|
|||
@TEST-EXEC: btest-rst-cmd bro -r ${TRACES}/http/proxy.pcap ${DOC_ROOT}/httpmonitor/http_proxy_02.bro
|
1
testing/btest/doc/sphinx/http_proxy_03.btest
Normal file
1
testing/btest/doc/sphinx/http_proxy_03.btest
Normal file
|
@ -0,0 +1 @@
|
|||
@TEST-EXEC: btest-rst-cmd bro -r ${TRACES}/http/proxy.pcap ${DOC_ROOT}/httpmonitor/http_proxy_03.bro
|
2
testing/btest/doc/sphinx/http_proxy_04.btest
Normal file
2
testing/btest/doc/sphinx/http_proxy_04.btest
Normal file
|
@ -0,0 +1,2 @@
|
|||
@TEST-EXEC: btest-rst-cmd bro -r ${TRACES}/http/proxy.pcap ${DOC_ROOT}/httpmonitor/http_proxy_04.bro
|
||||
@TEST-EXEC: btest-rst-include notice.log
|
|
@ -0,0 +1,28 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
file_extraction.bro
|
||||
|
||||
|
||||
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_new(f: fa_file)
|
||||
{
|
||||
if ( f$source != "HTTP" )
|
||||
return;
|
||||
|
||||
if ( ! f?$mime_type )
|
||||
return;
|
||||
|
||||
if ( f$mime_type !in mime_to_ext )
|
||||
return;
|
||||
|
||||
local fname = fmt("%s-%s.%s", f$source, f$id, mime_to_ext[f$mime_type]);
|
||||
print fmt("Extracting file %s", fname);
|
||||
Files::add_analyzer(f, Files::ANALYZER_EXTRACT, [$extract_filename=fname]);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
http_proxy_01.bro
|
||||
|
||||
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);
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
http_proxy_02.bro
|
||||
|
||||
|
||||
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);
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
http_proxy_03.bro
|
||||
|
||||
|
||||
@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);
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
http_proxy_04.bro
|
||||
|
||||
@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]);
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
mimestats.bro
|
||||
|
||||
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 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)]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
mimestats.bro
|
||||
|
||||
local r1: SumStats::Reducer = [$stream="mime.bytes",
|
||||
$apply=set(SumStats::SUM)];
|
||||
local r2: SumStats::Reducer = [$stream="mime.hits",
|
||||
$apply=set(SumStats::UNIQUE)];
|
|
@ -0,0 +1,18 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
mimestats.bro
|
||||
|
||||
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);
|
||||
}]);
|
|
@ -0,0 +1,68 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
mimestats.bro
|
||||
|
||||
@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]);
|
||||
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)]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
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)]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
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)]);
|
||||
}]);
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
# @TEST-EXEC: cat %INPUT >output && btest-diff output
|
||||
|
||||
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)]);
|
||||
}
|
||||
}
|
2
testing/btest/doc/sphinx/mimestats.btest
Normal file
2
testing/btest/doc/sphinx/mimestats.btest
Normal file
|
@ -0,0 +1,2 @@
|
|||
@TEST-EXEC: btest-rst-cmd bro -r ${TRACES}/http/bro.org.pcap ${DOC_ROOT}/mimestats/mimestats.bro
|
||||
@TEST-EXEC: btest-rst-include mime_metrics.log
|
Loading…
Add table
Add a link
Reference in a new issue