Merge remote-tracking branch 'origin/master' into topic/johanna/openflow

This commit is contained in:
Johanna Amann 2015-05-12 13:08:32 -07:00
commit a51ee45e05
264 changed files with 7452 additions and 4927 deletions

212
CHANGES
View file

@ -1,4 +1,216 @@
2.4-beta | 2015-05-07 21:55:31 -0700
* Release 2.4-beta.
* Update local-compat.test (Johanna Amann)
2.3-913 | 2015-05-06 09:58:00 -0700
* Add /sbin to PATH in btest.cfg and remove duplicate default_path.
(Daniel Thayer)
2.3-911 | 2015-05-04 09:58:09 -0700
* Update usage output and list of command line options. (Daniel
Thayer)
* Fix to ssh/geo-data.bro for unset directions. (Vlad Grigorescu)
* Improve SIP logging and remove reporter messages. (Seth Hall)
2.3-905 | 2015-04-29 17:01:30 -0700
* Improve SIP logging and remove reporter messages. (Seth Hall)
2.3-903 | 2015-04-27 17:27:59 -0700
* BIT-1350: Improve record coercion type checking. (Jon Siwek)
2.3-901 | 2015-04-27 17:25:27 -0700
* BIT-1384: Remove -O (optimize scripts) command-line option, which
hadn't been working for a while already. (Jon Siwek)
2.3-899 | 2015-04-27 17:22:42 -0700
* Fix the -J/--set-seed cmd-line option. (Daniel Thayer)
* Remove unused -l, -L, and -Z cmd-line options. (Daniel Thayer)
2.3-892 | 2015-04-27 08:22:22 -0700
* Fix typos in the Broker BIF documentation. (Daniel Thayer)
* Update installation instructions and remove outdated references.
(Johanna Amann)
* Easier support for systems with tcmalloc_minimal installed. (Seth
Hall)
2.3-884 | 2015-04-23 12:30:15 -0500
* Fix some outdated documentation unit tests. (Jon Siwek)
2.3-883 | 2015-04-23 07:10:36 -0700
* Fix -N option to work with builtin plugins as well. (Robin Sommer)
2.3-882 | 2015-04-23 06:59:40 -0700
* Add missing .pac dependencies for some binpac analyzer targets.
(Jon Siwek)
2.3-879 | 2015-04-22 10:38:07 -0500
* Fix compile errors. (Jon Siwek)
2.3-878 | 2015-04-22 08:21:23 -0700
* Fix another compiler warning in DTLS. (Johanna Amann)
2.3-877 | 2015-04-21 20:14:16 -0700
* Adding missing include. (Robin Sommer)
2.3-876 | 2015-04-21 16:40:10 -0700
* Attempt at fixing a potential std::length_error exception in RDP
analyzer. Addresses BIT-1337. (Robin Sommer)
* Fixing compile problem caused by overeager factorization. (Robin
Sommer)
2.3-874 | 2015-04-21 16:09:20 -0700
* Change details of escaping when logging/printing. (Seth Hall/Robin
Sommer)
- Log files now escape non-printable characters consistently
as "\xXX'. Furthermore, backslashes are escaped as "\\",
making the representation fully reversible.
- When escaping via script-level functions (escape_string,
clean), we likewise now escape consistently with "\xXX" and
"\\".
- There's no "alternative" output style anymore, i.e., fmt()
'%A' qualifier is gone.
Addresses BIT-1333.
* Remove several BroString escaping methods that are no longer
useful. (Seth Hall)
2.3-864 | 2015-04-21 15:24:02 -0700
* A SIP protocol analyzer. (Vlad Grigorescu)
Activity gets logged into sip.log. It generates the following
events:
event sip_request(c: connection, method: string, original_URI: string, version: string);
event sip_reply(c: connection, version: string, code: count, reason: string);
event sip_header(c: connection, is_orig: bool, name: string, value: string);
event sip_all_headers(c: connection, is_orig: bool, hlist: mime_header_list);
event sip_begin_entity(c: connection, is_orig: bool);
event sip_end_entity(c: connection, is_orig: bool);
The analyzer support SIP over UDP currently.
* BIT-1343: Factor common ASN.1 code from RDP, SNMP, and Kerberos
analyzers. (Jon Siwek/Robin Sommer)
2.3-838 | 2015-04-21 13:40:12 -0700
* BIT-1373: Fix vector index assignment reference count bug. (Jon Siwek)
2.3-836 | 2015-04-21 13:37:31 -0700
* Fix SSH direction field being unset. Addresses BIT-1365. (Vlad
Grigorescu)
2.3-835 | 2015-04-21 16:36:00 -0500
* Clarify Broker examples. (Jon Siwek)
2.3-833 | 2015-04-21 12:38:32 -0700
* A Kerberos protocol analyzer. (Vlad Grigorescu)
Activity gets logged into kerberos.log. It generates the following
events:
event krb_as_request(c: connection, msg: KRB::KDC_Request);
event krb_as_response(c: connection, msg: KRB::KDC_Response);
event krb_tgs_request(c: connection, msg: KRB::KDC_Request);
event krb_tgs_response(c: connection, msg: KRB::KDC_Response);
event krb_ap_request(c: connection, ticket: KRB::Ticket, opts: KRB::AP_Options);
event krb_priv(c: connection, is_orig: bool);
event krb_safe(c: connection, is_orig: bool, msg: KRB::SAFE_Msg);
event krb_cred(c: connection, is_orig: bool, tickets: KRB::Ticket_Vector);
event krb_error(c: connection, msg: KRB::Error_Msg);
2.3-793 | 2015-04-20 20:51:00 -0700
* Add decoding of PROXY-AUTHORIZATION header to HTTP analyze,
treating it the same as AUTHORIZATION. (Josh Liburdi)
* Remove deprecated fields "hot" and "addl" from the connection
record. Remove the functions append_addl() and
append_addl_marker(). (Robin Sommer)
* Removing the NetFlow analyzer, which hasn't been used anymore
since then corresponding command-line option went away. (Robin
Sommer)
2.3-787 | 2015-04-20 19:15:23 -0700
* A file analyzer for Portable Executables. (Vlad Grigorescu/Seth
Hall).
Activity gets logged into pe.log. It generates the following
events:
event pe_dos_header(f: fa_file, h: PE::DOSHeader);
event pe_dos_code(f: fa_file, code: string);
event pe_file_header(f: fa_file, h: PE::FileHeader);
event pe_optional_header(f: fa_file, h: PE::OptionalHeader);
event pe_section_header(f: fa_file, h: PE::SectionHeader);
2.3-741 | 2015-04-20 13:12:39 -0700
* API changes to file analysis mime type detection. Removed
"file_mime_type" and "file_mime_types" event, replacing them with
a new event called "file_metadata_inferred". Addresses BIT-1368.
(Jon Siwek)
* A large series of improvements for file type identification. This
inludes a many signature updates (new types, cleanup, performance
improvments) and splitting out signatures into subfiles. (Seth
Hall)
* Fix an issue with files having gaps before the bof_buffer is
filled, which could lead to file type identification not working
correctly. (Seth Hall)
* Fix an issue with packet loss in HTTP file reporting for file type
identification wasn't working correctly zero-length bodies. (Seth
Hall)
* X.509 certificates are now populating files.log with the mime type
application/pkix-cert. (Seth Hall)
* Normalized some FILE_ANALYSIS debug messages. (Seth Hall)
2.3-725 | 2015-04-20 12:54:54 -0700
* Updating submodule(s).
2.3-724 | 2015-04-20 14:11:02 -0500
* Fix uninitialized field in raw input reader. (Jon Siwek)
2.3-722 | 2015-04-20 12:59:03 -0500
* Remove unneeded documentation cross-referencing. (Jon Siwek)

View file

@ -113,7 +113,7 @@ if (NOT DISABLE_PERFTOOLS)
find_package(GooglePerftools)
endif ()
if (GOOGLEPERFTOOLS_FOUND)
if (GOOGLEPERFTOOLS_FOUND OR TCMALLOC_FOUND)
set(HAVE_PERFTOOLS true)
# Non-Linux systems may not be well-supported by gperftools, so
# require explicit request from user to enable it in that case.

107
NEWS
View file

@ -13,10 +13,12 @@ New Functionality
- Bro now has support for external plugins that can extend its core
functionality, like protocol/file analysis, via shared libraries.
Plugins can be developed and distributed externally, and will be
pulled in dynamically at startup. Currently, a plugin can provide
custom protocol analyzers, file analyzers, log writers, input
readers, packet sources and dumpers, and new built-in functions. A
plugin can furthermore hook into Bro's processing at a number of
pulled in dynamically at startup (the environment variables
BRO_PLUGIN_PATH and BRO_PLUGIN_ACTIVATE can be used to specify the
locations and names of plugins to activate). Currently, a plugin
can provide custom protocol analyzers, file analyzers, log writers,
input readers, packet sources and dumpers, and new built-in functions.
A plugin can furthermore hook into Bro's processing at a number of
places to add custom logic.
See https://www.bro.org/sphinx-git/devel/plugins.html for more
@ -25,17 +27,37 @@ New Functionality
- Bro now has support for the MySQL wire protocol. Activity gets
logged into mysql.log.
- Bro now parses DTLS traffic.
- Bro now parses DTLS traffic. Activity gets logged into ssl.log.
- Bro now has an RDP analyzer.
- Bro now has support for the Kerberos KRB5 protocol over TCP and
UDP. Activity gets logged into kerberos.log.
- Bro now features a completely rewritten, enhanced SSH analyzer, with
a set of addedd events being generated. A lot more information about
SSH sessions is logged. The analyzer is able to determine if logins
failed or succeeded in most circumstances.
- Bro now has an RDP analyzer. Activity gets logged into rdp.log.
- Bro now has a file analyzer for Portable Executables. Activity gets
logged into pe.log.
- Bro now has support for the SIP protocol over UDP. Activity gets
logged into sip.log.
- Bro now features a completely rewritten, enhanced SSH analyzer. The
new analyzer is able to determine if logins failed or succeeded in
most circumstances, logs a lot more more information about SSH
sessions, supports v1, and introduces the intelligence type
``Intel::PUBKEY_HASH`` and location ``SSH::IN_SERVER_HOST_KEY``. The
analayzer also generates a set of additional events
(``ssh_auth_successful``, ``ssh_auth_failed``, ``ssh_capabilities``,
``ssh2_server_host_key``, ``ssh1_server_host_key``,
``ssh_encrypted_packet``, ``ssh2_dh_server_params``,
``ssh2_gss_error``, ``ssh2_ecc_key``). See next section for
incompatible SSH changes.
- Bro's file analysis now supports reassembly of files that are not
transferred/seen sequentially.
transferred/seen sequentially. The default file reassembly buffer
size is set with the ``Files::reassembly_buffer_size`` variable.
- Bro's file type identification has been greatly improved (new file types,
bug fixes, and performance improvements).
- Bro's scripting language now has a ``while`` statement::
@ -61,7 +83,7 @@ New Functionality
C++11 compiler (e.g. GCC 4.8+ or Clang 3.3+).
Broker will become a mandatory dependency in future Bro versions and
replace the current communcation and serialization system.
replace the current communication and serialization system.
- Add --enable-c++11 configure flag to compile Bro's source code in
C++11 mode with a corresponding compiler. Note that 2.4 will be the
@ -69,10 +91,10 @@ New Functionality
- The SSL analysis now alerts when encountering SSL connections with
old protocol versions or unsafe cipher suites. It also gained
extended reporting of weak keys, caching of already valdidated
certificates, full support TLS record defragmentation. SSL generally
extended reporting of weak keys, caching of already validated
certificates, and full support for TLS record defragmentation. SSL generally
became much more robust and added several fields to ssl.log (while
removing some other).
removing some others).
- A new icmp_sent_payload event provides access to ICMP payload.
@ -85,6 +107,9 @@ New Functionality
threshold in terms of packets or bytes. The primary API for that
functionality is in base/protocols/conn/thresholds.bro.
- There is a new command-line option -Q/--time that prints Bro's execution
time and memory usage to stderr.
- BroControl now has a new command "deploy" which is equivalent to running
the "check", "install", "stop", and "start" commands (in that order).
@ -114,14 +139,17 @@ Changed Functionality
- File analysis
* Removed ``fa_file`` record's ``mime_type`` and ``mime_types``
fields. The events ``file_mime_type`` and ``file_mime_types``
have been added which contain the same information. The
``mime_type`` field of ``Files::Info`` also still has this info.
fields. The event ``file_sniff`` has been added which provides
the same information. The ``mime_type`` field of ``Files::Info``
also still has this info.
* The earliest point that new mime type information is available is
in the ``file_mime_type`` event which comes after the ``file_new``
and ``file_over_new_connection`` events. Scripts which inspected
mime type info within those events will need to be adapted.
in the ``file_sniff`` event which comes after the ``file_new`` and
``file_over_new_connection`` events. Scripts which inspected mime
type info within those events will need to be adapted. (Note: for
users that worked w/ versions of Bro from git, for a while there was
also an event called ``file_mime_type`` which is now replaced with
the ``file_sniff`` event).
* Removed ``Files::add_analyzers_for_mime_type`` function.
@ -130,10 +158,22 @@ Changed Functionality
reassembly for non-sequential files, "offset" can be obtained
with other information already available -- adding together
``seen_bytes`` and ``missed_bytes`` fields of the ``fa_file``
record gives the how many bytes have been written so far (i.e.
record gives how many bytes have been written so far (i.e.
the "offset").
- has_valid_octets: now uses a string_vec parameter instead of
- The SSH changes come with a few incompatibilities. The following
events have been renamed:
* ``SSH::heuristic_failed_login`` to ``SSH::ssh_auth_failed``
* ``SSH::heuristic_successful_login`` to ``SSH::ssh_auth_successful``
The ``SSH::Info`` status field has been removed and replaced with
the ``auth_success`` field. This field has been changed from a
string that was previously ``success``, ``failure`` or
``undetermined`` to a boolean. a boolean that is ``T``, ``F``, or
unset.
- The has_valid_octets function now uses a string_vec parameter instead of
string_array.
- conn.log gained a new field local_resp that works like local_orig,
@ -176,6 +216,25 @@ Changed Functionality
- BroControl now sends all normal command output (i.e., not error messages)
to stdout. Error messages are still sent to stderr, however.
- The capability of processing NetFlow input has been removed for the
time being. Therefore, the -y/--flowfile and -Y/--netflow command-line
options have been removed, and the netflow_v5_header and netflow_v5_record
events have been removed.
- The -D/--dfa-size command-line option has been removed.
- The -L/--rule-benchmark command-line option has been removed.
- The -O/--optimize command-line option has been removed.
- The deprecated fields "hot" and "addl" have been removed from the
connection record. Likewise, the functions append_addl() and
append_addl_marker() have been removed.
- Log files now escape non-printable characters consistently as "\xXX'.
Furthermore, backslashes are escaped as "\\", making the
representation fully reversible.
Deprecated Functionality
------------------------
@ -185,7 +244,7 @@ Deprecated Functionality
concatenation/extraction functions. Note that the new functions use
0-based indexing, rather than 1-based.
The full list of now deprecation functions is:
The full list of now deprecated functions is:
* split: use split_string instead.

View file

@ -1 +1 @@
2.3-722
2.4-beta

@ -1 +1 @@
Subproject commit 544330932e7cd4615d6d19f63907e8aa2acebb9e
Subproject commit 4f33233aef5539ae4f12c6d0e4338247833c3900

@ -1 +1 @@
Subproject commit 462e300bf9c37dcc39b70a4c2d89d19f7351c804
Subproject commit a2d290a832c35ad11f3fabb19812bcae2ff089cd

@ -1 +1 @@
Subproject commit 45276b39a946d70095c983753cd321ad07dcf285
Subproject commit 74bb4bbd949e61e099178f8a97499d3f1355de8b

@ -1 +1 @@
Subproject commit e864a0949e52a797f4000194b5c2980cf3618deb
Subproject commit 97c17d21725e42b36f4b49579077ecdc28ddb86a

@ -1 +1 @@
Subproject commit 0c25c1daa7dcf885dd16cc1b725295dc36decafe
Subproject commit b02fefd5cf78c1576e59c106f5211ce5ae47cfdd

@ -1 +1 @@
Subproject commit d69df586c91531db0c3abe838b10a429dda4fa87
Subproject commit 80b42ee3e4503783b6720855b28e83ff1658c22b

@ -1 +1 @@
Subproject commit 7a14085394e54a950e477eb4fafb3827ff8dbdc3
Subproject commit e1ea9f67cfe3d6a81e0c1479ced0b9aa73e77c87

2
cmake

@ -1 +1 @@
Subproject commit 2fd35ab6a6245a005828c32f0aa87eb21698c054
Subproject commit 6406fb79d30df8d7956110ce65a97d18e4bc8c3b

View file

@ -1,5 +1,5 @@
const broker_port: port &redef;
const broker_port: port = 9999/tcp &redef;
redef exit_only_after_terminate = T;
redef BrokerComm::endpoint_name = "connector";

View file

@ -1,5 +1,5 @@
const broker_port: port &redef;
const broker_port: port = 9999/tcp &redef;
redef exit_only_after_terminate = T;
redef BrokerComm::endpoint_name = "listener";

View file

@ -1,4 +1,4 @@
const broker_port: port &redef;
const broker_port: port = 9999/tcp &redef;
redef exit_only_after_terminate = T;
redef BrokerComm::endpoint_name = "connector";
global my_event: event(msg: string, c: count);

View file

@ -1,5 +1,5 @@
const broker_port: port &redef;
const broker_port: port = 9999/tcp &redef;
redef exit_only_after_terminate = T;
redef BrokerComm::endpoint_name = "listener";
global msg_count = 0;

View file

@ -1,6 +1,6 @@
@load ./testlog
const broker_port: port &redef;
const broker_port: port = 9999/tcp &redef;
redef exit_only_after_terminate = T;
redef BrokerComm::endpoint_name = "connector";
redef Log::enable_local_logging = F;

View file

@ -1,6 +1,6 @@
@load ./testlog
const broker_port: port &redef;
const broker_port: port = 9999/tcp &redef;
redef exit_only_after_terminate = T;
redef BrokerComm::endpoint_name = "listener";

View file

@ -1,4 +1,4 @@
const broker_port: port &redef;
const broker_port: port = 9999/tcp &redef;
redef exit_only_after_terminate = T;
redef BrokerComm::endpoint_name = "connector";

View file

@ -1,5 +1,5 @@
const broker_port: port &redef;
const broker_port: port = 9999/tcp &redef;
redef exit_only_after_terminate = T;
redef BrokerComm::endpoint_name = "listener";
global msg_count = 0;

View file

@ -1,4 +1,4 @@
const broker_port: port &redef;
const broker_port: port = 9999/tcp &redef;
redef exit_only_after_terminate = T;
global h: opaque of BrokerStore::Handle;

View file

@ -1,4 +1,4 @@
const broker_port: port &redef;
const broker_port: port = 9999/tcp &redef;
redef exit_only_after_terminate = T;
global h: opaque of BrokerStore::Handle;

View file

@ -1,7 +1,8 @@
event file_mime_type(f: fa_file, mime_type: string)
event file_sniff(f: fa_file, meta: fa_metadata)
{
if ( ! meta?$mime_type ) return;
print "new file", f$id;
if ( mime_type == "text/plain" )
if ( meta$mime_type == "text/plain" )
Files::add_analyzer(f, Files::ANALYZER_MD5);
}

View file

@ -7,15 +7,18 @@ global mime_to_ext: table[string] of string = {
["text/html"] = "html",
};
event file_mime_type(f: fa_file, mime_type: string)
event file_sniff(f: fa_file, meta: fa_metadata)
{
if ( f$source != "HTTP" )
return;
if ( mime_type !in mime_to_ext )
if ( ! meta?$mime_type )
return;
local fname = fmt("%s-%s.%s", f$source, f$id, mime_to_ext[mime_type]);
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]);
}

View file

@ -68,7 +68,7 @@ that ``bash`` and ``python`` are in your ``PATH``):
.. console::
sudo pkg_add -r bash cmake swig bison python perl
sudo pkg_add -r bash cmake swig bison python perl py27-sqlite3
* Mac OS X:
@ -113,19 +113,15 @@ Using Pre-Built Binary Release Packages
=======================================
See the `bro downloads page`_ for currently supported/targeted
platforms for binary releases.
platforms for binary releases and for installation instructions.
* RPM
* Linux Packages
.. console::
sudo yum localinstall Bro-*.rpm
* DEB
.. console::
sudo gdebi Bro-*.deb
Linux based binary installations are usually performed by adding
information about the Bro packages to the respective system packaging
tool. Theen the usual system utilities such as ``apt``, ``yum``
or ``zyppper`` are used to perforn the installation. By default,
installations of binary packages will go into ``/opt/bro``.
* MacOS Disk Image with Installer
@ -133,8 +129,6 @@ platforms for binary releases.
Everything installed by the package will go into ``/opt/bro``.
The primary install prefix for binary packages is ``/opt/bro``.
Non-MacOS packages that include BroControl also put variable/runtime
data (e.g. Bro logs) in ``/var/opt/bro``.
Installing from Source
==========================

View file

@ -363,7 +363,7 @@ decrypted from HTTP streams is stored in
excerpt from :doc:`/scripts/base/protocols/http/main.bro` below.
.. btest-include:: ${BRO_SRC_ROOT}/scripts/base/protocols/http/main.bro
:lines: 9-11,20-22,121
:lines: 9-11,20-22,125
Because the constant was declared with the ``&redef`` attribute, if we
needed to turn this option on globally, we could do so by adding the

View file

@ -0,0 +1,2 @@
@load ./consts
@load ./main

View file

@ -0,0 +1,184 @@
module PE;
export {
const machine_types: table[count] of string = {
[0x00] = "UNKNOWN",
[0x1d3] = "AM33",
[0x8664] = "AMD64",
[0x1c0] = "ARM",
[0x1c4] = "ARMNT",
[0xaa64] = "ARM64",
[0xebc] = "EBC",
[0x14c] = "I386",
[0x200] = "IA64",
[0x9041] = "M32R",
[0x266] = "MIPS16",
[0x366] = "MIPSFPU",
[0x466] = "MIPSFPU16",
[0x1f0] = "POWERPC",
[0x1f1] = "POWERPCFP",
[0x166] = "R4000",
[0x1a2] = "SH3",
[0x1a3] = "SH3DSP",
[0x1a6] = "SH4",
[0x1a8] = "SH5",
[0x1c2] = "THUMB",
[0x169] = "WCEMIPSV2"
} &default=function(i: count):string { return fmt("unknown-%d", i); };
const file_characteristics: table[count] of string = {
[0x1] = "RELOCS_STRIPPED",
[0x2] = "EXECUTABLE_IMAGE",
[0x4] = "LINE_NUMS_STRIPPED",
[0x8] = "LOCAL_SYMS_STRIPPED",
[0x10] = "AGGRESSIVE_WS_TRIM",
[0x20] = "LARGE_ADDRESS_AWARE",
[0x80] = "BYTES_REVERSED_LO",
[0x100] = "32BIT_MACHINE",
[0x200] = "DEBUG_STRIPPED",
[0x400] = "REMOVABLE_RUN_FROM_SWAP",
[0x800] = "NET_RUN_FROM_SWAP",
[0x1000] = "SYSTEM",
[0x2000] = "DLL",
[0x4000] = "UP_SYSTEM_ONLY",
[0x8000] = "BYTES_REVERSED_HI"
} &default=function(i: count):string { return fmt("unknown-%d", i); };
const dll_characteristics: table[count] of string = {
[0x40] = "DYNAMIC_BASE",
[0x80] = "FORCE_INTEGRITY",
[0x100] = "NX_COMPAT",
[0x200] = "NO_ISOLATION",
[0x400] = "NO_SEH",
[0x800] = "NO_BIND",
[0x2000] = "WDM_DRIVER",
[0x8000] = "TERMINAL_SERVER_AWARE"
} &default=function(i: count):string { return fmt("unknown-%d", i); };
const windows_subsystems: table[count] of string = {
[0] = "UNKNOWN",
[1] = "NATIVE",
[2] = "WINDOWS_GUI",
[3] = "WINDOWS_CUI",
[7] = "POSIX_CUI",
[9] = "WINDOWS_CE_GUI",
[10] = "EFI_APPLICATION",
[11] = "EFI_BOOT_SERVICE_DRIVER",
[12] = "EFI_RUNTIME_DRIVER",
[13] = "EFI_ROM",
[14] = "XBOX"
} &default=function(i: count):string { return fmt("unknown-%d", i); };
const directories: table[count] of string = {
[0] = "Export Table",
[1] = "Import Table",
[2] = "Resource Table",
[3] = "Exception Table",
[4] = "Certificate Table",
[5] = "Base Relocation Table",
[6] = "Debug",
[7] = "Architecture",
[8] = "Global Ptr",
[9] = "TLS Table",
[10] = "Load Config Table",
[11] = "Bound Import",
[12] = "IAT",
[13] = "Delay Import Descriptor",
[14] = "CLR Runtime Header",
[15] = "Reserved"
} &default=function(i: count):string { return fmt("unknown-%d", i); };
const section_characteristics: table[count] of string = {
[0x8] = "TYPE_NO_PAD",
[0x20] = "CNT_CODE",
[0x40] = "CNT_INITIALIZED_DATA",
[0x80] = "CNT_UNINITIALIZED_DATA",
[0x100] = "LNK_OTHER",
[0x200] = "LNK_INFO",
[0x800] = "LNK_REMOVE",
[0x1000] = "LNK_COMDAT",
[0x8000] = "GPREL",
[0x20000] = "MEM_16BIT",
[0x40000] = "MEM_LOCKED",
[0x80000] = "MEM_PRELOAD",
[0x100000] = "ALIGN_1BYTES",
[0x200000] = "ALIGN_2BYTES",
[0x300000] = "ALIGN_4BYTES",
[0x400000] = "ALIGN_8BYTES",
[0x500000] = "ALIGN_16BYTES",
[0x600000] = "ALIGN_32BYTES",
[0x700000] = "ALIGN_64BYTES",
[0x800000] = "ALIGN_128BYTES",
[0x900000] = "ALIGN_256BYTES",
[0xa00000] = "ALIGN_512BYTES",
[0xb00000] = "ALIGN_1024BYTES",
[0xc00000] = "ALIGN_2048BYTES",
[0xd00000] = "ALIGN_4096BYTES",
[0xe00000] = "ALIGN_8192BYTES",
[0x1000000] = "LNK_NRELOC_OVFL",
[0x2000000] = "MEM_DISCARDABLE",
[0x4000000] = "MEM_NOT_CACHED",
[0x8000000] = "MEM_NOT_PAGED",
[0x10000000] = "MEM_SHARED",
[0x20000000] = "MEM_EXECUTE",
[0x40000000] = "MEM_READ",
[0x80000000] = "MEM_WRITE"
} &default=function(i: count):string { return fmt("unknown-%d", i); };
const os_versions: table[count, count] of string = {
[10,0] = "Windows 10",
[6,4] = "Windows 10 Technical Preview",
[6,3] = "Windows 8.1 or Server 2012 R2",
[6,2] = "Windows 8 or Server 2012",
[6,1] = "Windows 7 or Server 2008 R2",
[6,0] = "Windows Vista or Server 2008",
[5,2] = "Windows XP x64 or Server 2003",
[5,1] = "Windows XP",
[5,0] = "Windows 2000",
[4,90] = "Windows Me",
[4,10] = "Windows 98",
[4,0] = "Windows 95 or NT 4.0",
[3,51] = "Windows NT 3.51",
[3,50] = "Windows NT 3.5",
[3,2] = "Windows 3.2",
[3,11] = "Windows for Workgroups 3.11",
[3,10] = "Windows 3.1 or NT 3.1",
[3,0] = "Windows 3.0",
[2,11] = "Windows 2.11",
[2,10] = "Windows 2.10",
[2,0] = "Windows 2.0",
[1,4] = "Windows 1.04",
[1,3] = "Windows 1.03",
[1,1] = "Windows 1.01",
[1,0] = "Windows 1.0",
} &default=function(i: count, j: count):string { return fmt("unknown-%d.%d", i, j); };
const section_descs: table[string] of string = {
[".bss"] = "Uninitialized data",
[".cormeta"] = "CLR metadata that indicates that the object file contains managed code",
[".data"] = "Initialized data",
[".debug$F"] = "Generated FPO debug information",
[".debug$P"] = "Precompiled debug types",
[".debug$S"] = "Debug symbols",
[".debug$T"] = "Debug types",
[".drective"] = "Linker options",
[".edata"] = "Export tables",
[".idata"] = "Import tables",
[".idlsym"] = "Includes registered SEH to support IDL attributes",
[".pdata"] = "Exception information",
[".rdata"] = "Read-only initialized data",
[".reloc"] = "Image relocations",
[".rsrc"] = "Resource directory",
[".sbss"] = "GP-relative uninitialized data",
[".sdata"] = "GP-relative initialized data",
[".srdata"] = "GP-relative read-only data",
[".sxdata"] = "Registered exception handler data",
[".text"] = "Executable code",
[".tls"] = "Thread-local storage",
[".tls$"] = "Thread-local storage",
[".vsdata"] = "GP-relative initialized data",
[".xdata"] = "Exception information",
} &default=function(i: string):string { return fmt("unknown-%s", i); };
}

View file

@ -0,0 +1,137 @@
module PE;
@load ./consts.bro
export {
redef enum Log::ID += { LOG };
type Info: record {
## Current timestamp.
ts: time &log;
## File id of this portable executable file.
id: string &log;
## The target machine that the file was compiled for.
machine: string &log &optional;
## The time that the file was created at.
compile_ts: time &log &optional;
## The required operating system.
os: string &log &optional;
## The subsystem that is required to run this file.
subsystem: string &log &optional;
## Is the file an executable, or just an object file?
is_exe: bool &log &default=T;
## Is the file a 64-bit executable?
is_64bit: bool &log &default=T;
## Does the file support Address Space Layout Randomization?
uses_aslr: bool &log &default=F;
## Does the file support Data Execution Prevention?
uses_dep: bool &log &default=F;
## Does the file enforce code integrity checks?
uses_code_integrity: bool &log &default=F;
## Does the file use structured exception handing?
uses_seh: bool &log &default=T;
## Does the file have an import table?
has_import_table: bool &log &optional;
## Does the file have an export table?
has_export_table: bool &log &optional;
## Does the file have an attribute certificate table?
has_cert_table: bool &log &optional;
## Does the file have a debug table?
has_debug_data: bool &log &optional;
## The names of the sections, in order.
section_names: vector of string &log &optional;
};
## Event for accessing logged records.
global log_pe: event(rec: Info);
## A hook that gets called when we first see a PE file.
global set_file: hook(f: fa_file);
}
redef record fa_file += {
pe: Info &optional;
};
const pe_mime_types = { "application/x-dosexec" };
event bro_init() &priority=5
{
Files::register_for_mime_types(Files::ANALYZER_PE, pe_mime_types);
Log::create_stream(LOG, [$columns=Info, $ev=log_pe, $path="pe"]);
}
hook set_file(f: fa_file) &priority=5
{
if ( ! f?$pe )
f$pe = [$ts=network_time(), $id=f$id];
}
event pe_dos_header(f: fa_file, h: PE::DOSHeader) &priority=5
{
hook set_file(f);
}
event pe_file_header(f: fa_file, h: PE::FileHeader) &priority=5
{
hook set_file(f);
f$pe$machine = machine_types[h$machine];
f$pe$compile_ts = h$ts;
f$pe$is_exe = ( h$optional_header_size > 0 );
for ( c in h$characteristics )
{
if ( file_characteristics[c] == "32BIT_MACHINE" )
f$pe$is_64bit = F;
}
}
event pe_optional_header(f: fa_file, h: PE::OptionalHeader) &priority=5
{
hook set_file(f);
# Only EXEs have optional headers
if ( ! f$pe$is_exe )
return;
f$pe$os = os_versions[h$os_version_major, h$os_version_minor];
f$pe$subsystem = windows_subsystems[h$subsystem];
for ( c in h$dll_characteristics )
{
if ( dll_characteristics[c] == "DYNAMIC_BASE" )
f$pe$uses_aslr = T;
if ( dll_characteristics[c] == "FORCE_INTEGRITY" )
f$pe$uses_code_integrity = T;
if ( dll_characteristics[c] == "NX_COMPAT" )
f$pe$uses_dep = T;
if ( dll_characteristics[c] == "NO_SEH" )
f$pe$uses_seh = F;
}
f$pe$has_export_table = (|h$table_sizes| > 0 && h$table_sizes[0] > 0);
f$pe$has_import_table = (|h$table_sizes| > 1 && h$table_sizes[1] > 0);
f$pe$has_cert_table = (|h$table_sizes| > 4 && h$table_sizes[4] > 0);
f$pe$has_debug_data = (|h$table_sizes| > 6 && h$table_sizes[6] > 0);
}
event pe_section_header(f: fa_file, h: PE::SectionHeader) &priority=5
{
hook set_file(f);
# Only EXEs have section headers
if ( ! f$pe$is_exe )
return;
if ( ! f$pe?$section_names )
f$pe$section_names = vector();
f$pe$section_names[|f$pe$section_names|] = h$name;
}
event file_state_remove(f: fa_file) &priority=-5
{
if ( f?$pe && f$pe?$machine )
Log::write(LOG, f$pe);
}

View file

@ -47,6 +47,9 @@ redef record Files::Info += {
event x509_certificate(f: fa_file, cert_ref: opaque of x509, cert: X509::Certificate) &priority=5
{
if ( ! f$info?$mime_type )
f$info$mime_type = "application/pkix-cert";
f$info$x509 = [$ts=f$info$ts, $id=f$id, $certificate=cert, $handle=cert_ref];
}

View file

@ -1,3 +1,9 @@
@load-sigs ./archive
@load-sigs ./audio
@load-sigs ./font
@load-sigs ./general
@load-sigs ./image
@load-sigs ./msoffice
@load-sigs ./video
@load-sigs ./libmagic

View file

@ -0,0 +1,176 @@
signature file-tar {
file-magic /^[[:print:]\x00]{100}([[:digit:]\x20]{7}\x00){3}([[:digit:]\x20]{11}\x00){2}([[:digit:]\x00\x20]{7}[\x20\x00])[0-7\x00]/
file-mime "application/x-tar", 100
}
# This is low priority so that files using zip as a
# container will be identified correctly.
signature file-zip {
file-mime "application/zip", 10
file-magic /^PK\x03\x04.{2}/
}
# Multivolume Zip archive
signature file-multi-zip {
file-mime "application/zip", 10
file-magic /^PK\x07\x08PK\x03\x04/
}
# RAR
signature file-rar {
file-mime "application/x-rar", 70
file-magic /^Rar!/
}
# GZIP
signature file-gzip {
file-mime "application/x-gzip", 100
file-magic /\x1f\x8b/
}
# Microsoft Cabinet
signature file-ms-cab {
file-mime "application/vnd.ms-cab-compressed", 110
file-magic /^MSCF\x00\x00\x00\x00/
}
# Mac OS X DMG files
signature file-dmg {
file-magic /^(\x78\x01\x73\x0D\x62\x62\x60|\x78\xDA\x63\x60\x18\x05|\x78\x01\x63\x60\x18\x05|\x78\xDA\x73\x0D|\x78[\x01\xDA]\xED[\xD0-\xD9])/
file-mime "application/x-dmg", 100
}
# XAR (eXtensible ARchive) format.
# Mac OS X uses this for the .pkg format.
signature file-xar {
file-magic /^xar\!/
file-mime "application/x-xar", 100
}
# RPM
signature file-magic-auto352 {
file-mime "application/x-rpm", 70
file-magic /^(drpm|\xed\xab\xee\xdb)/
}
# StuffIt
signature file-stuffit {
file-mime "application/x-stuffit", 70
file-magic /^(SIT\x21|StuffIt)/
}
# Archived data
signature file-x-archive {
file-mime "application/x-archive", 70
file-magic /^!?<ar(ch)?>/
}
# ARC archive data
signature file-arc {
file-mime "application/x-arc", 70
file-magic /^[\x00-\x7f]{2}[\x02-\x0a\x14\x48]\x1a/
}
# EET archive
signature file-eet {
file-mime "application/x-eet", 70
file-magic /^\x1e\xe7\xff\x00/
}
# Zoo archive
signature file-zoo {
file-mime "application/x-zoo", 70
file-magic /^.{20}\xdc\xa7\xc4\xfd/
}
# LZ4 compressed data (legacy format)
signature file-lz4-legacy {
file-mime "application/x-lz4", 70
file-magic /(\x02\x21\x4c\x18)/
}
# LZ4 compressed data
signature file-lz4 {
file-mime "application/x-lz4", 70
file-magic /^\x04\x22\x4d\x18/
}
# LRZIP compressed data
signature file-lrzip {
file-mime "application/x-lrzip", 1
file-magic /^LRZI/
}
# LZIP compressed data
signature file-lzip {
file-mime "application/x-lzip", 70
file-magic /^LZIP/
}
# Self-extracting PKZIP archive
signature file-magic-auto434 {
file-mime "application/zip", 340
file-magic /^MZ.{28}(Copyright 1989\x2d1990 PKWARE Inc|PKLITE Copr)\x2e/
}
# LHA archive (LZH)
signature file-lzh {
file-mime "application/x-lzh", 80
file-magic /^.{2}-(lh[ abcdex0-9]|lz[s2-8]|lz[s2-8]|pm[s012]|pc1)-/
}
# WARC Archive
signature file-warc {
file-mime "application/warc", 50
file-magic /^WARC\x2f/
}
# 7-zip archive data
signature file-7zip {
file-mime "application/x-7z-compressed", 50
file-magic /^7z\xbc\xaf\x27\x1c/
}
# XZ compressed data
signature file-xz {
file-mime "application/x-xz", 90
file-magic /^\xfd7zXZ\x00/
}
# LHa self-extracting archive
signature file-magic-auto436 {
file-mime "application/x-lha", 120
file-magic /^MZ.{34}LH[aA]\x27s SFX/
}
# ARJ archive data
signature file-arj {
file-mime "application/x-arj", 50
file-magic /^\x60\xea/
}
# Byte-swapped cpio archive
signature file-bs-cpio {
file-mime "application/x-cpio", 50
file-magic /(\x71\xc7|\xc7\x71)/
}
# CPIO archive
signature file-cpio {
file-mime "application/x-cpio", 50
file-magic /^(\xc7\x71|\x71\xc7)/
}
# Compress'd data
signature file-compress {
file-mime "application/x-compress", 50
file-magic /^\x1f\x9d/
}
# LZMA compressed data
signature file-lzma {
file-mime "application/x-lzma", 71
file-magic /^\x5d\x00\x00/
}

View file

@ -0,0 +1,13 @@
# MPEG v3 audio
signature file-mpeg-audio {
file-mime "audio/mpeg", 20
file-magic /^\xff[\xe2\xe3\xf2\xf3\xf6\xf7\xfa\xfb\xfc\xfd]/
}
# MPEG v4 audio
signature file-m4a {
file-mime "audio/m4a", 70
file-magic /^....ftyp(m4a)/
}

View file

@ -0,0 +1,41 @@
# Web Open Font Format
signature file-woff {
file-magic /^wOFF/
file-mime "application/font-woff", 70
}
# TrueType font
signature file-ttf {
file-mime "application/x-font-ttf", 80
file-magic /^\x00\x01\x00\x00\x00/
}
signature file-embedded-opentype {
file-mime "application/vnd.ms-fontobject", 50
file-magic /^.{34}LP/
}
# X11 SNF font
signature file-snf {
file-mime "application/x-font-sfn", 70
file-magic /^(\x04\x00\x00\x00|\x00\x00\x00\x04).{100}(\x04\x00\x00\x00|\x00\x00\x00\x04)/
}
# OpenType font
signature file-opentype {
file-mime "application/vnd.ms-opentype", 70
file-magic /^OTTO/
}
# FrameMaker Font file
signature file-maker-screen-font {
file-mime "application/x-mif", 190
file-magic /^\x3cMakerScreenFont/
}
# >0 string,=SplineFontDB: (len=13), ["Spline Font Database "], swap_endian=0
signature file-spline-font-db {
file-mime "application/vnd.font-fontforge-sfd", 160
file-magic /^SplineFontDB\x3a/
}

View file

@ -1,18 +1,87 @@
# General purpose file magic signatures.
# Plaintext
# (Including BOMs for UTF-8, 16, and 32)
signature file-plaintext {
file-magic /^([[:print:][:space:]]{10})/
file-mime "text/plain", -20
file-mime "text/plain", -20
file-magic /^(\xef\xbb\xbf|(\x00\x00)?\xfe\xff|\xff\xfe(\x00\x00)?)?[[:space:]\x20-\x7E]{10}/
}
signature file-tar {
file-magic /^[[:print:]\x00]{100}([[:digit:]\x20]{7}\x00){3}([[:digit:]\x20]{11}\x00){2}([[:digit:]\x00\x20]{7}[\x20\x00])[0-7\x00]/
file-mime "application/x-tar", 100
signature file-json {
file-mime "text/json", 1
file-magic /^(\xef\xbb\xbf)?[\x0d\x0a[:blank:]]*\{[\x0d\x0a[:blank:]]*(["][^"]{1,}["]|[a-zA-Z][a-zA-Z0-9\\_]*)[\x0d\x0a[:blank:]]*:[\x0d\x0a[:blank:]]*(["]|\[|\{|[0-9]|true|false)/
}
signature file-zip {
file-mime "application/zip", 10
file-magic /^PK\x03\x04.{2}/
signature file-json2 {
file-mime "text/json", 1
file-magic /^(\xef\xbb\xbf)?[\x0d\x0a[:blank:]]*\[[\x0d\x0a[:blank:]]*(((["][^"]{1,}["]|[0-9]{1,}(\.[0-9]{1,})?|true|false)[\x0d\x0a[:blank:]]*,)|\{|\[)[\x0d\x0a[:blank:]]*/
}
# Match empty JSON documents.
signature file-json3 {
file-mime "text/json", 0
file-magic /^(\xef\xbb\xbf)?[\x0d\x0a[:blank:]]*(\[\]|\{\})[\x0d\x0a[:blank:]]*$/
}
signature file-xml {
file-mime "application/xml", 10
file-magic /^(\xef\xbb\xbf)?([\x0d\x0a[:blank:]]*(<!--.*-->)?[\x0d\x0a[:blank:]]*)*<\?xml /
}
signature file-xhtml {
file-mime "text/html", 100
file-magic /^(\xef\xbb\xbf)?([\x0d\x0a[:blank:]]*(<!--.*-->)?[\x0d\x0a[:blank:]]*)*(<\?xml .*\?>)?([\x0d\x0a[:blank:]]*(<!--.*-->)?[\x0d\x0a[:blank:]]*)*<(![dD][oO][cC][tT][yY][pP][eE] {1,}[hH][tT][mM][lL]|[hH][tT][mM][lL]|[mM][eE][tT][aA] {1,}[hH][tT][tT][pP]-[eE][qQ][uU][iI][vV])/
}
signature file-html {
file-mime "text/html", 49
file-magic /^(\xef\xbb\xbf)?([\x0d\x0a[:blank:]]*(<!--.*-->)?[\x0d\x0a[:blank:]]*)*(<\?xml .*\?>)?([\x0d\x0a[:blank:]]*(<!--.*-->)?[\x0d\x0a[:blank:]]*)*<![dD][oO][cC][tT][yY][pP][eE] {1,}[hH][tT][mM][lL]/
}
signature file-html2 {
file-mime "text/html", 20
file-magic /^(\xef\xbb\xbf)?([\x0d\x0a[:blank:]]*(<!--.*-->)?[\x0d\x0a[:blank:]]*)*(<\?xml .*\?>)?([\x0d\x0a[:blank:]]*(<!--.*-->)?[\x0d\x0a[:blank:]]*)*<([hH][eE][aA][dD]|[hH][tT][mM][lL]|[tT][iI][tT][lL][eE]|[bB][oO][dD][yY])/
}
signature file-rss {
file-mime "text/rss", 90
file-magic /^(\xef\xbb\xbf)?([\x0d\x0a[:blank:]]*(<!--.*-->)?[\x0d\x0a[:blank:]]*)*(<\?xml .*\?>)?([\x0d\x0a[:blank:]]*(<!--.*-->)?[\x0d\x0a[:blank:]]*)*<[rR][sS][sS]/
}
signature file-atom {
file-mime "text/atom", 100
file-magic /^(\xef\xbb\xbf)?([\x0d\x0a[:blank:]]*(<!--.*-->)?[\x0d\x0a[:blank:]]*)*(<\?xml .*\?>)?([\x0d\x0a[:blank:]]*(<!--.*-->)?[\x0d\x0a[:blank:]]*)*<([rR][sS][sS][^>]*xmlns:atom|[fF][eE][eE][dD][^>]*xmlns=["']?http:\/\/www.w3.org\/2005\/Atom["']?)/
}
signature file-soap {
file-mime "application/soap+xml", 49
file-magic /^(\xef\xbb\xbf)?([\x0d\x0a[:blank:]]*(<!--.*-->)?[\x0d\x0a[:blank:]]*)*(<\?xml .*\?>)?([\x0d\x0a[:blank:]]*(<!--.*-->)?[\x0d\x0a[:blank:]]*)*<[sS][oO][aA][pP](-[eE][nN][vV])?:[eE][nN][vV][eE][lL][oO][pP][eE]/
}
signature file-cross-domain-policy {
file-mime "text/x-cross-domain-policy", 49
file-magic /^([\x0d\x0a[:blank:]]*(<!--.*-->)?[\x0d\x0a[:blank:]]*)*(<\?xml .*\?>)?([\x0d\x0a[:blank:]]*(<!--.*-->)?[\x0d\x0a[:blank:]]*)*<![dD][oO][cC][tT][yY][pP][eE] {1,}[cC][rR][oO][sS][sS]-[dD][oO][mM][aA][iI][nN]-[pP][oO][lL][iI][cC][yY]/
}
signature file-cross-domain-policy2 {
file-mime "text/x-cross-domain-policy", 49
file-magic /^([\x0d\x0a[:blank:]]*(<!--.*-->)?[\x0d\x0a[:blank:]]*)*(<\?xml .*\?>)?([\x0d\x0a[:blank:]]*(<!--.*-->)?[\x0d\x0a[:blank:]]*)*<[cC][rR][oO][sS][sS]-[dD][oO][mM][aA][iI][nN]-[pP][oO][lL][iI][cC][yY]/
}
signature file-xmlrpc {
file-mime "application/xml-rpc", 49
file-magic /^(\xef\xbb\xbf)?([\x0d\x0a[:blank:]]*(<!--.*-->)?[\x0d\x0a[:blank:]]*)*(<\?xml .*\?>)?([\x0d\x0a[:blank:]]*(<!--.*-->)?[\x0d\x0a[:blank:]]*)*<[mM][eE][tT][hH][oO][dD][rR][eE][sS][pP][oO][nN][sS][eE]>/
}
signature file-coldfusion {
file-mime "magnus-internal/cold-fusion", 20
file-magic /^([\x0d\x0a[:blank:]]*(<!--.*-->)?)*<(CFPARAM|CFSET|CFIF)/
}
# Microsoft LNK files
signature file-lnk {
file-mime "application/x-ms-shortcut", 49
file-magic /^\x4C\x00\x00\x00\x01\x14\x02\x00\x00\x00\x00\x00\xC0\x00\x00\x00\x00\x10\x00\x00\x00\x46/
}
signature file-jar {
@ -21,8 +90,20 @@ signature file-jar {
}
signature file-java-applet {
file-magic /^\xca\xfe\xba\xbe...[\x2e-\x34]/
file-mime "application/x-java-applet", 71
file-magic /^\xca\xfe\xba\xbe...[\x2d-\x34]/
}
# OCSP requests over HTTP.
signature file-ocsp-request {
file-magic /^.{11,19}\x06\x05\x2b\x0e\x03\x02\x1a/
file-mime "application/ocsp-request", 71
}
# OCSP responses over HTTP.
signature file-ocsp-response {
file-magic /^.{11,19}\x06\x09\x2B\x06\x01\x05\x05\x07\x30\x01\x01/
file-mime "application/ocsp-response", 71
}
# Shockwave flash
@ -37,12 +118,6 @@ signature file-tnef {
file-mime "application/vnd.ms-tnef", 100
}
# Mac OS X DMG files
signature file-dmg {
file-magic /^(\x78\x01\x73\x0D\x62\x62\x60|\x78\xDA\x63\x60\x18\x05|\x78\x01\x63\x60\x18\x05|\x78\xDA\x73\x0D|\x78[\x01\xDA]\xED[\xD0-\xD9])/
file-mime "application/x-dmg", 100
}
# Mac OS X Mach-O executable
signature file-mach-o {
file-magic /^[\xce\xcf]\xfa\xed\xfe/
@ -55,13 +130,6 @@ signature file-mach-o-universal {
file-mime "application/x-mach-o-executable", 100
}
# XAR (eXtensible ARchive) format.
# Mac OS X uses this for the .pkg format.
signature file-xar {
file-magic /^xar\!/
file-mime "application/x-xar", 100
}
signature file-pkcs7 {
file-magic /^MIME-Version:.*protocol=\"application\/pkcs7-signature\"/
file-mime "application/pkcs7-signature", 100
@ -79,16 +147,6 @@ signature file-jnlp {
file-mime "application/x-java-jnlp-file", 100
}
signature file-ico {
file-magic /^\x00\x00\x01\x00/
file-mime "image/x-icon", 70
}
signature file-cur {
file-magic /^\x00\x00\x02\x00/
file-mime "image/x-cursor", 70
}
signature file-pcap {
file-magic /^(\xa1\xb2\xc3\xd4|\xd4\xc3\xb2\xa1)/
file-mime "application/vnd.tcpdump.pcap", 70
@ -119,7 +177,58 @@ signature file-python {
file-mime "text/x-python", 60
}
signature file-awk {
file-mime "text/x-awk", 60
file-magic /^\x23\x21[^\n]{1,15}bin\/(env[[:space:]]+)?(g|n)?awk/
}
signature file-tcl {
file-mime "text/x-tcl", 60
file-magic /^\x23\x21[^\n]{1,15}bin\/(env[[:space:]]+)?(wish|tcl)/
}
signature file-lua {
file-mime "text/x-lua", 49
file-magic /^\x23\x21[^\n]{1,15}bin\/(env[[:space:]]+)?lua/
}
signature file-javascript {
file-mime "application/javascript", 60
file-magic /^\x23\x21[^\n]{1,15}bin\/(env[[:space:]]+)?node(js)?/
}
signature file-javascript2 {
file-mime "application/javascript", 60
file-magic /^[\x0d\x0a[:blank:]]*<[sS][cC][rR][iI][pP][tT][[:blank:]]+([tT][yY][pP][eE]|[lL][aA][nN][gG][uU][aA][gG][eE])=['"]?([tT][eE][xX][tT]\/)?[jJ][aA][vV][aA][sS][cC][rR][iI][pP][tT]/
}
signature file-javascript3 {
file-mime "application/javascript", 60
# This seems to be a somewhat common idiom in javascript.
file-magic /^[\x0d\x0a[:blank:]]*for \(;;\);/
}
signature file-javascript4 {
file-mime "application/javascript", 60
file-magic /^[\x0d\x0a[:blank:]]*document\.write(ln)?[:blank:]?\(/
}
signature file-javascript5 {
file-mime "application/javascript", 60
file-magic /^\(function\(\)[[:blank:]\n]*\{/
}
signature file-javascript6 {
file-mime "application/javascript", 60
file-magic /^[\x0d\x0a[:blank:]]*<script>[\x0d\x0a[:blank:]]*(var|function) /
}
signature file-php {
file-mime "text/x-php", 60
file-magic /^\x23\x21[^\n]{1,15}bin\/(env[[:space:]]+)?php/
}
signature file-php2 {
file-magic /^.*<\?php/
file-mime "text/x-php", 40
}
@ -135,3 +244,23 @@ signature file-skp {
file-magic /^\xFF\xFE\xFF\x0E\x53\x00\x6B\x00\x65\x00\x74\x00\x63\x00\x68\x00\x55\x00\x70\x00\x20\x00\x4D\x00\x6F\x00\x64\x00\x65\x00\x6C\x00/
file-mime "application/skp", 100
}
signature file-elf-object {
file-mime "application/x-object", 50
file-magic /\x7fELF[\x01\x02](\x01.{10}\x01\x00|\x02.{10}\x00\x01)/
}
signature file-elf {
file-mime "application/x-executable", 50
file-magic /\x7fELF[\x01\x02](\x01.{10}\x02\x00|\x02.{10}\x00\x02)/
}
signature file-elf-sharedlib {
file-mime "application/x-sharedlib", 50
file-magic /\x7fELF[\x01\x02](\x01.{10}\x03\x00|\x02.{10}\x00\x03)/
}
signature file-elf-coredump {
file-mime "application/x-coredump", 50
file-magic /\x7fELF[\x01\x02](\x01.{10}\x04\x00|\x02.{10}\x00\x04)/
}

View file

@ -0,0 +1,166 @@
signature file-tiff {
file-mime "image/tiff", 70
file-magic /^(MM\x00[\x2a\x2b]|II[\x2a\x2b]\x00)/
}
signature file-gif {
file-mime "image/gif", 70
file-magic /^GIF8/
}
# JPEG image
signature file-jpeg {
file-mime "image/jpeg", 52
file-magic /^\xff\xd8/
}
signature file-bmp {
file-mime "image/x-ms-bmp", 50
file-magic /BM.{12}[\x0c\x28\x40\x6c\x7c\x80]\x00/
}
signature file-ico {
file-magic /^\x00\x00\x01\x00/
file-mime "image/x-icon", 70
}
signature file-cur {
file-magic /^\x00\x00\x02\x00/
file-mime "image/x-cursor", 70
}
signature file-magic-auto289 {
file-mime "image/vnd.adobe.photoshop", 70
file-magic /^8BPS/
}
signature file-png {
file-mime "image/png", 110
file-magic /^\x89PNG/
}
# JPEG 2000
signature file-jp2 {
file-mime "image/jp2", 60
file-magic /.{4}ftypjp2/
}
# JPEG 2000
signature file-jp22 {
file-mime "image/jp2", 70
file-magic /\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a.{8}jp2 /
}
# JPEG 2000
signature file-jpx {
file-mime "image/jpx", 70
file-magic /\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a.{8}jpx /
}
# JPEG 2000
signature file-jpm {
file-mime "image/jpm", 70
file-magic /\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a.{8}jpm /
}
# Xcursor image
signature file-x-cursor {
file-mime "image/x-xcursor", 70
file-magic /^Xcur/
}
# NIFF image
signature file-niff {
file-mime "image/x-niff", 70
file-magic /^IIN1/
}
# OpenEXR image
signature file-openexr {
file-mime "image/x-exr", 70
file-magic /^\x76\x2f\x31\x01/
}
# DPX image
signature file-dpx {
file-mime "image/x-dpx", 70
file-magic /^SDPX/
}
# Cartesian Perceptual Compression image
signature file-cpi {
file-mime "image/x-cpi", 70
file-magic /(CPC\xb2)/
}
signature file-orf {
file-mime "image/x-olympus-orf", 70
file-magic /IIR[OS]|MMOR/
}
# Foveon X3F raw image
signature file-x3r {
file-mime "image/x-x3f", 70
file-magic /^FOVb/
}
# Paint.NET image
signature file-paint-net {
file-mime "image/x-paintnet", 70
file-magic /^PDN3/
}
# Corel Draw Picture
signature file-coreldraw {
file-mime "image/x-coreldraw", 70
file-magic /^RIFF....CDR[A6]/
}
# Netpbm PAM image
signature file-netbpm{
file-mime "image/x-portable-pixmap", 50
file-magic /^P7/
}
# JPEG 2000 image
signature file-jpeg-2000 {
file-mime "image/jp2", 50
file-magic /^....jP/
}
# DjVU Images
signature file-djvu {
file-mime "image/vnd.djvu", 70
file-magic /AT\x26TFORM.{4}(DJV[MUI]|THUM)/
}
# DWG AutoDesk AutoCAD
signature file-dwg {
file-mime "image/vnd.dwg", 90
file-magic /^(AC[12]\.|AC10)/
}
# GIMP XCF image
signature file-gimp-xcf {
file-mime "image/x-xcf", 110
file-magic /^gimp xcf/
}
# Polar Monitor Bitmap text
signature file-polar-monitor-bitmap {
file-mime "image/x-polar-monitor-bitmap", 160
file-magic /^\x5bBitmapInfo2\x5d/
}
# Award BIOS bitmap
signature file-award-bitmap {
file-mime "image/x-award-bmp", 20
file-magic /^AWBM/
}
# Award BIOS Logo, 136 x 84
signature file-award-bios-logo {
file-mime "image/x-award-bioslogo", 50
file-magic /^\x11[\x06\x09]/
}

File diff suppressed because it is too large Load diff

View file

@ -26,3 +26,9 @@ signature file-pptx {
file-magic /^PK\x03\x04.{26}(\[Content_Types\]\.xml|_rels\x2f\.rels|ppt\x2f).*PK\x03\x04.{26}ppt\x2f/
file-mime "application/vnd.openxmlformats-officedocument.presentationml.presentation", 80
}
signature file-msaccess {
file-mime "application/x-msaccess", 180
file-magic /.{4}Standard (Jet|ACE) DB\x00/
}

View file

@ -0,0 +1,96 @@
# Macromedia Flash Video
signature file-flv {
file-mime "video/x-flv", 60
file-magic /^FLV/
}
# FLI animation
signature file-fli {
file-mime "video/x-fli", 50
file-magic /^.{4}\x11\xaf/
}
# FLC animation
signature file-flc {
file-mime "video/x-flc", 50
file-magic /^.{4}\x12\xaf/
}
# Motion JPEG 2000
signature file-mj2 {
file-mime "video/mj2", 70
file-magic /\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a.{8}mjp2/
}
# MNG video
signature file-mng {
file-mime "video/x-mng", 70
file-magic /^\x8aMNG/
}
# JNG video
signature file-jng {
file-mime "video/x-jng", 70
file-magic /^\x8bJNG/
}
# Generic MPEG container
signature file-mpeg {
file-mime "video/mpeg", 50
file-magic /(\x00\x00\x01[\xb0-\xbb])/
}
# MPV
signature file-mpv {
file-mime "video/mpv", 71
file-magic /(\x00\x00\x01\xb3)/
}
# H.264
signature file-h264 {
file-mime "video/h264", 41
file-magic /(\x00\x00\x00\x01)([\x07\x27\x47\x67\x87\xa7\xc7\xe7])/
}
# WebM video
signature file-webm {
file-mime "video/webm", 70
file-magic /(\x1a\x45\xdf\xa3)(.*)(B\x82)(.{1})(webm)/
}
# Matroska video
signature file-matroska {
file-mime "video/x-matroska", 110
file-magic /(\x1a\x45\xdf\xa3)(.*)(B\x82)(.{1})(matroska)/
}
# MP2P
signature file-mp2p {
file-mime "video/mp2p", 21
file-magic /\x00\x00\x01\xba([\x40-\x7f\xc0-\xff])/
}
# Silicon Graphics video
signature file-sgi-movie {
file-mime "video/x-sgi-movie", 70
file-magic /^MOVI/
}
# Apple QuickTime movie
signature file-quicktime {
file-mime "video/quicktime", 70
file-magic /^....(mdat|moov)/
}
# MPEG v4 video
signature file-mp4 {
file-mime "video/mp4", 70
file-magic /^....ftyp(isom|mp4[12])/
}
# 3GPP Video
signature file-3gpp {
file-mime "video/3gpp", 60
file-magic /^....ftyp(3g[egps2]|avc1|mmp4)/
}

View file

@ -129,12 +129,11 @@ export {
## files based on the detected mime type of the file.
const analyze_by_mime_type_automatically = T &redef;
## The default setting for if the file reassembler is enabled for
## each file.
## The default setting for file reassembly.
const enable_reassembler = T &redef;
## The default per-file reassembly buffer size.
const reassembly_buffer_size = 1048576 &redef;
const reassembly_buffer_size = 524288 &redef;
## Allows the file reassembler to be used if it's necessary because the
## file is transferred out of order.
@ -484,16 +483,19 @@ event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priori
add f$info$rx_hosts[f$is_orig ? cid$resp_h : cid$orig_h];
}
event file_mime_type(f: fa_file, mime_type: string) &priority=10
event file_sniff(f: fa_file, meta: fa_metadata) &priority=10
{
set_info(f);
f$info$mime_type = mime_type;
if ( ! meta?$mime_type )
return;
f$info$mime_type = meta$mime_type;
if ( analyze_by_mime_type_automatically &&
mime_type in mime_type_to_analyzers )
meta$mime_type in mime_type_to_analyzers )
{
local analyzers = mime_type_to_analyzers[mime_type];
local analyzers = mime_type_to_analyzers[meta$mime_type];
for ( a in analyzers )
{
add f$info$analyzers[Files::analyzer_name(a)];

View file

@ -345,8 +345,6 @@ type connection: record {
## to parse the same data. If so, all will be recorded. Also note that
## the recorded services are independent of any transport-level protocols.
service: set[string];
addl: string; ##< Deprecated.
hot: count; ##< Deprecated.
history: string; ##< State history of connections. See *history* in :bro:see:`Conn::Info`.
## A globally unique connection identifier. For each connection, Bro
## creates an ID that is very likely unique across independent Bro runs.
@ -426,6 +424,14 @@ type fa_file: record {
bof_buffer: string &optional;
} &redef;
## Metadata that's been inferred about a particular file.
type fa_metadata: record {
## The strongest matching mime type if one was discovered.
mime_type: string &optional;
## All matching mime types if any were discovered.
mime_types: mime_matches &optional;
};
## Fields of a SYN packet.
##
## .. bro:see:: connection_SYN_packet
@ -1093,27 +1099,6 @@ const ENDIAN_LITTLE = 1; ##< Little endian.
const ENDIAN_BIG = 2; ##< Big endian.
const ENDIAN_CONFUSED = 3; ##< Tried to determine endian, but failed.
## Deprecated.
function append_addl(c: connection, addl: string)
{
if ( c$addl == "" )
c$addl= addl;
else if ( addl !in c$addl )
c$addl = fmt("%s %s", c$addl, addl);
}
## Deprecated.
function append_addl_marker(c: connection, addl: string, marker: string)
{
if ( c$addl == "" )
c$addl= addl;
else if ( addl !in c$addl )
c$addl = fmt("%s%s%s", c$addl, marker, addl);
}
# Values for :bro:see:`set_contents_file` *direction* argument.
# todo:: these should go into an enum to make them autodoc'able
const CONTENTS_NONE = 0; ##< Turn off recording of contents.
@ -2559,6 +2544,145 @@ type irc_join_info: record {
## .. bro:see:: irc_join_message
type irc_join_list: set[irc_join_info];
module PE;
export {
type PE::DOSHeader: record {
## The magic number of a portable executable file ("MZ").
signature : string;
## The number of bytes in the last page that are used.
used_bytes_in_last_page : count;
## The number of pages in the file that are part of the PE file itself.
file_in_pages : count;
## Number of relocation entries stored after the header.
num_reloc_items : count;
## Number of paragraphs in the header.
header_in_paragraphs : count;
## Number of paragraps of additional memory that the program will need.
min_extra_paragraphs : count;
## Maximum number of paragraphs of additional memory.
max_extra_paragraphs : count;
## Relative value of the stack segment.
init_relative_ss : count;
## Initial value of the SP register.
init_sp : count;
## Checksum. The 16-bit sum of all words in the file should be 0. Normally not set.
checksum : count;
## Initial value of the IP register.
init_ip : count;
## Initial value of the CS register (relative to the initial segment).
init_relative_cs : count;
## Offset of the first relocation table.
addr_of_reloc_table : count;
## Overlays allow you to append data to the end of the file. If this is the main program,
## this will be 0.
overlay_num : count;
## OEM identifier.
oem_id : count;
## Additional OEM info, specific to oem_id.
oem_info : count;
## Address of the new EXE header.
addr_of_new_exe_header : count;
};
type PE::FileHeader: record {
## The target machine that the file was compiled for.
machine : count;
## The time that the file was created at.
ts : time;
## Pointer to the symbol table.
sym_table_ptr : count;
## Number of symbols.
num_syms : count;
## The size of the optional header.
optional_header_size : count;
## Bit flags that determine if this file is executable, non-relocatable, and/or a DLL.
characteristics : set[count];
};
type PE::OptionalHeader: record {
## PE32 or PE32+ indicator.
magic : count;
## The major version of the linker used to create the PE.
major_linker_version : count;
## The minor version of the linker used to create the PE.
minor_linker_version : count;
## Size of the .text section.
size_of_code : count;
## Size of the .data section.
size_of_init_data : count;
## Size of the .bss section.
size_of_uninit_data : count;
## The relative virtual address (RVA) of the entry point.
addr_of_entry_point : count;
## The relative virtual address (RVA) of the .text section.
base_of_code : count;
## The relative virtual address (RVA) of the .data section.
base_of_data : count &optional;
## Preferred memory location for the image to be based at.
image_base : count;
## The alignment (in bytes) of sections when they're loaded in memory.
section_alignment : count;
## The alignment (in bytes) of the raw data of sections.
file_alignment : count;
## The major version of the required OS.
os_version_major : count;
## The minor version of the required OS.
os_version_minor : count;
## The major version of this image.
major_image_version : count;
## The minor version of this image.
minor_image_version : count;
## The major version of the subsystem required to run this file.
major_subsys_version : count;
## The minor version of the subsystem required to run this file.
minor_subsys_version : count;
## The size (in bytes) of the iamge as the image is loaded in memory.
size_of_image : count;
## The size (in bytes) of the headers, rounded up to file_alignment.
size_of_headers : count;
## The image file checksum.
checksum : count;
## The subsystem that's required to run this image.
subsystem : count;
## Bit flags that determine how to execute or load this file.
dll_characteristics : set[count];
## A vector with the sizes of various tables and strings that are
## defined in the optional header data directories. Examples include
## the import table, the resource table, and debug information.
table_sizes : vector of count;
};
## Record for Portable Executable (PE) section headers.
type PE::SectionHeader: record {
## The name of the section
name : string;
## The total size of the section when loaded into memory.
virtual_size : count;
## The relative virtual address (RVA) of the section.
virtual_addr : count;
## The size of the initialized data for the section, as it is
## in the file on disk.
size_of_raw_data : count;
## The virtual address of the initialized dat for the section,
## as it is in the file on disk.
ptr_to_raw_data : count;
## The file pointer to the beginning of relocation entries for
## the section.
ptr_to_relocs : count;
## The file pointer to the beginning of line-number entries for
## the section.
ptr_to_line_nums : count;
## The number of relocation entries for the section.
num_of_relocs : count;
## The number of line-number entrie for the section.
num_of_line_nums : count;
## Bit-flags that describe the characteristics of the section.
characteristics : set[count];
};
}
module GLOBAL;
## Deprecated.
##
## .. todo:: Remove. It's still declared internally but doesn't seem used anywhere
@ -2683,60 +2807,6 @@ global generate_OS_version_event: set[subnet] &redef;
# number>``), which were seen during the sample.
type load_sample_info: set[string];
## ID for NetFlow header. This is primarily a means to sort together NetFlow
## headers and flow records at the script level.
type nfheader_id: record {
## Name of the NetFlow file (e.g., ``netflow.dat``) or the receiving
## socket address (e.g., ``127.0.0.1:5555``), or an explicit name if
## specified to ``-y`` or ``-Y``.
rcvr_id: string;
## A serial number, ignoring any overflows.
pdu_id: count;
};
## A NetFlow v5 header.
##
## .. bro:see:: netflow_v5_header
type nf_v5_header: record {
h_id: nfheader_id; ##< ID for sorting.
cnt: count; ##< TODO.
sysuptime: interval; ##< Router's uptime.
exporttime: time; ##< When the data was exported.
flow_seq: count; ##< Sequence number.
eng_type: count; ##< Engine type.
eng_id: count; ##< Engine ID.
sample_int: count; ##< Sampling interval.
exporter: addr; ##< Exporter address.
};
## A NetFlow v5 record.
##
## .. bro:see:: netflow_v5_record
type nf_v5_record: record {
h_id: nfheader_id; ##< ID for sorting.
id: conn_id; ##< Connection ID.
nexthop: addr; ##< Address of next hop.
input: count; ##< Input interface.
output: count; ##< Output interface.
pkts: count; ##< Number of packets.
octets: count; ##< Number of bytes.
first: time; ##< Timestamp of first packet.
last: time; ##< Timestamp of last packet.
tcpflag_fin: bool; ##< FIN flag for TCP flows.
tcpflag_syn: bool; ##< SYN flag for TCP flows.
tcpflag_rst: bool; ##< RST flag for TCP flows.
tcpflag_psh: bool; ##< PSH flag for TCP flows.
tcpflag_ack: bool; ##< ACK flag for TCP flows.
tcpflag_urg: bool; ##< URG flag for TCP flows.
proto: count; ##< IP protocol.
tos: count; ##< Type of service.
src_as: count; ##< Source AS.
dst_as: count; ##< Destination AS.
src_mask: count; ##< Source mask.
dst_mask: count; ##< Destination mask.
};
## A BitTorrent peer.
##
## .. bro:see:: bittorrent_peer_set
@ -3057,6 +3127,186 @@ export {
};
}
@load base/bif/plugins/Bro_KRB.types.bif
module KRB;
export {
## KDC Options. See :rfc:`4120`
type KRB::KDC_Options: record {
## The ticket to be issued should have its forwardable flag set.
forwardable : bool;
## A (TGT) request for forwarding.
forwarded : bool;
## The ticket to be issued should have its proxiable flag set.
proxiable : bool;
## A request for a proxy.
proxy : bool;
## The ticket to be issued should have its may-postdate flag set.
allow_postdate : bool;
## A request for a postdated ticket.
postdated : bool;
## The ticket to be issued should have its renewable flag set.
renewable : bool;
## Reserved for opt_hardware_auth
opt_hardware_auth : bool;
## Request that the KDC not check the transited field of a TGT against
## the policy of the local realm before it will issue derivative tickets
## based on the TGT.
disable_transited_check : bool;
## If a ticket with the requested lifetime cannot be issued, a renewable
## ticket is acceptable
renewable_ok : bool;
## The ticket for the end server is to be encrypted in the session key
## from the additional TGT provided
enc_tkt_in_skey : bool;
## The request is for a renewal
renew : bool;
## The request is to validate a postdated ticket.
validate : bool;
};
## AP Options. See :rfc:`4120`
type KRB::AP_Options: record {
## Indicates that user-to-user-authentication is in use
use_session_key : bool;
## Mutual authentication is required
mutual_required : bool;
};
## Used in a few places in the Kerberos analyzer for elements
## that have a type and a string value.
type KRB::Type_Value: record {
## The data type
data_type : count;
## The data value
val : string;
};
type KRB::Type_Value_Vector: vector of KRB::Type_Value;
## A Kerberos host address See :rfc:`4120`.
type KRB::Host_Address: record {
## IPv4 or IPv6 address
ip : addr &log &optional;
## NetBIOS address
netbios : string &log &optional;
## Some other type that we don't support yet
unknown : KRB::Type_Value &optional;
};
type KRB::Host_Address_Vector: vector of KRB::Host_Address;
## The data from the SAFE message. See :rfc:`4120`.
type KRB::SAFE_Msg: record {
## Protocol version number (5 for KRB5)
pvno : count;
## The message type (20 for SAFE_MSG)
msg_type : count;
## The application-specific data that is being passed
## from the sender to the reciever
data : string;
## Current time from the sender of the message
timestamp : time &optional;
## Sequence number used to detect replays
seq : count &optional;
## Sender address
sender : Host_Address &optional;
## Recipient address
recipient : Host_Address &optional;
};
## The data from the ERROR_MSG message. See :rfc:`4120`.
type KRB::Error_Msg: record {
## Protocol version number (5 for KRB5)
pvno : count;
## The message type (30 for ERROR_MSG)
msg_type : count;
## Current time on the client
client_time : time &optional;
## Current time on the server
server_time : time;
## The specific error code
error_code : count;
## Realm of the ticket
client_realm : string &optional;
## Name on the ticket
client_name : string &optional;
## Realm of the service
service_realm : string;
## Name of the service
service_name : string;
## Additional text to explain the error
error_text : string &optional;
## Optional pre-authentication data
pa_data : vector of KRB::Type_Value &optional;
};
## A Kerberos ticket. See :rfc:`4120`.
type KRB::Ticket: record {
## Protocol version number (5 for KRB5)
pvno : count;
## Realm
realm : string;
## Name of the service
service_name : string;
## Cipher the ticket was encrypted with
cipher : count;
};
type KRB::Ticket_Vector: vector of KRB::Ticket;
## The data from the AS_REQ and TGS_REQ messages. See :rfc:`4120`.
type KRB::KDC_Request: record {
## Protocol version number (5 for KRB5)
pvno : count;
## The message type (10 for AS_REQ, 12 for TGS_REQ)
msg_type : count;
## Optional pre-authentication data
pa_data : vector of KRB::Type_Value &optional;
## Options specified in the request
kdc_options : KRB::KDC_Options;
## Name on the ticket
client_name : string &optional;
## Realm of the service
service_realm : string;
## Name of the service
service_name : string &optional;
## Time the ticket is good from
from : time &optional;
## Time the ticket is good till
till : time;
## The requested renew-till time
rtime : time &optional;
## A random nonce generated by the client
nonce : count;
## The desired encryption algorithms, in order of preference
encryption_types : vector of count;
## Any additional addresses the ticket should be valid for
host_addrs : vector of KRB::Host_Address &optional;
## Additional tickets may be included for certain transactions
additional_tickets : vector of KRB::Ticket &optional;
};
## The data from the AS_REQ and TGS_REQ messages. See :rfc:`4120`.
type KRB::KDC_Response: record {
## Protocol version number (5 for KRB5)
pvno : count;
## The message type (11 for AS_REP, 13 for TGS_REP)
msg_type : count;
## Optional pre-authentication data
pa_data : vector of KRB::Type_Value &optional;
## Realm on the ticket
client_realm : string &optional;
## Name on the service
client_name : string;
## The ticket that was issued
ticket : KRB::Ticket;
};
}
module GLOBAL;
@load base/bif/event.bif

View file

@ -47,11 +47,13 @@
@load base/protocols/ftp
@load base/protocols/http
@load base/protocols/irc
@load base/protocols/krb
@load base/protocols/modbus
@load base/protocols/mysql
@load base/protocols/pop3
@load base/protocols/radius
@load base/protocols/rdp
@load base/protocols/sip
@load base/protocols/snmp
@load base/protocols/smtp
@load base/protocols/socks
@ -60,6 +62,7 @@
@load base/protocols/syslog
@load base/protocols/tunnels
@load base/files/pe
@load base/files/hash
@load base/files/extract
@load base/files/unified2

View file

@ -63,10 +63,13 @@ event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priori
f$ftp = ftp;
}
event file_mime_type(f: fa_file, mime_type: string) &priority=5
event file_sniff(f: fa_file, meta: fa_metadata) &priority=5
{
if ( ! f?$ftp )
return;
f$ftp$mime_type = mime_type;
if ( ! meta?$mime_type )
return;
f$ftp$mime_type = meta$mime_type;
}

View file

@ -43,7 +43,7 @@ export {
event http_begin_entity(c: connection, is_orig: bool) &priority=10
{
set_state(c, F, is_orig);
set_state(c, is_orig);
if ( is_orig )
++c$http$orig_mime_depth;
@ -93,24 +93,27 @@ event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priori
}
}
event file_mime_type(f: fa_file, mime_type: string) &priority=5
event file_sniff(f: fa_file, meta: fa_metadata) &priority=5
{
if ( ! f?$http || ! f?$is_orig )
return;
if ( ! meta?$mime_type )
return;
if ( f$is_orig )
{
if ( ! f$http?$orig_mime_types )
f$http$orig_mime_types = string_vec(mime_type);
f$http$orig_mime_types = string_vec(meta$mime_type);
else
f$http$orig_mime_types[|f$http$orig_mime_types|] = mime_type;
f$http$orig_mime_types[|f$http$orig_mime_types|] = meta$mime_type;
}
else
{
if ( ! f$http?$resp_mime_types )
f$http$resp_mime_types = string_vec(mime_type);
f$http$resp_mime_types = string_vec(meta$mime_type);
else
f$http$resp_mime_types[|f$http$resp_mime_types|] = mime_type;
f$http$resp_mime_types[|f$http$resp_mime_types|] = meta$mime_type;
}
}

View file

@ -89,6 +89,10 @@ export {
current_request: count &default=0;
## Current response in the pending queue.
current_response: count &default=0;
## Track the current deepest transaction.
## This is meant to cope with missing requests
## and responses.
trans_depth: count &default=0;
};
## A list of HTTP headers typically used to indicate proxied requests.
@ -150,13 +154,11 @@ function new_http_session(c: connection): Info
tmp$ts=network_time();
tmp$uid=c$uid;
tmp$id=c$id;
# $current_request is set prior to the Info record creation so we
# can use the value directly here.
tmp$trans_depth = c$http_state$current_request;
tmp$trans_depth = ++c$http_state$trans_depth;
return tmp;
}
function set_state(c: connection, request: bool, is_orig: bool)
function set_state(c: connection, is_orig: bool)
{
if ( ! c?$http_state )
{
@ -165,15 +167,20 @@ function set_state(c: connection, request: bool, is_orig: bool)
}
# These deal with new requests and responses.
if ( request || c$http_state$current_request !in c$http_state$pending )
c$http_state$pending[c$http_state$current_request] = new_http_session(c);
if ( ! is_orig && c$http_state$current_response !in c$http_state$pending )
c$http_state$pending[c$http_state$current_response] = new_http_session(c);
if ( is_orig )
{
if ( c$http_state$current_request !in c$http_state$pending )
c$http_state$pending[c$http_state$current_request] = new_http_session(c);
c$http = c$http_state$pending[c$http_state$current_request];
}
else
{
if ( c$http_state$current_response !in c$http_state$pending )
c$http_state$pending[c$http_state$current_response] = new_http_session(c);
c$http = c$http_state$pending[c$http_state$current_response];
}
}
event http_request(c: connection, method: string, original_URI: string,
@ -186,7 +193,7 @@ event http_request(c: connection, method: string, original_URI: string,
}
++c$http_state$current_request;
set_state(c, T, T);
set_state(c, T);
c$http$method = method;
c$http$uri = unescaped_URI;
@ -208,8 +215,10 @@ event http_reply(c: connection, version: string, code: count, reason: string) &p
if ( c$http_state$current_response !in c$http_state$pending ||
(c$http_state$pending[c$http_state$current_response]?$status_code &&
! code_in_range(c$http_state$pending[c$http_state$current_response]$status_code, 100, 199)) )
{
++c$http_state$current_response;
set_state(c, F, F);
}
set_state(c, F);
c$http$status_code = code;
c$http$status_msg = reason;
@ -233,7 +242,7 @@ event http_reply(c: connection, version: string, code: count, reason: string) &p
event http_header(c: connection, is_orig: bool, name: string, value: string) &priority=5
{
set_state(c, F, is_orig);
set_state(c, is_orig);
if ( is_orig ) # client headers
{
@ -257,7 +266,7 @@ event http_header(c: connection, is_orig: bool, name: string, value: string) &pr
add c$http$proxied[fmt("%s -> %s", name, value)];
}
else if ( name == "AUTHORIZATION" )
else if ( name == "AUTHORIZATION" || name == "PROXY-AUTHORIZATION" )
{
if ( /^[bB][aA][sS][iI][cC] / in value )
{
@ -278,12 +287,11 @@ event http_header(c: connection, is_orig: bool, name: string, value: string) &pr
}
}
}
}
event http_message_done(c: connection, is_orig: bool, stat: http_message_stat) &priority = 5
{
set_state(c, F, is_orig);
set_state(c, is_orig);
if ( is_orig )
c$http$request_body_len = stat$body_length;

View file

@ -42,8 +42,8 @@ event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priori
f$irc = irc;
}
event file_mime_type(f: fa_file, mime_type: string) &priority=5
event file_sniff(f: fa_file, meta: fa_metadata) &priority=5
{
if ( f?$irc )
f$irc$dcc_mime_type = mime_type;
if ( f?$irc && meta?$mime_type )
f$irc$dcc_mime_type = meta$mime_type;
}

View file

@ -0,0 +1,3 @@
@load ./main
@load ./files
@load-sigs ./dpd.sig

View file

@ -0,0 +1,99 @@
module KRB;
export {
const error_msg: table[count] of string = {
[0] = "KDC_ERR_NONE",
[1] = "KDC_ERR_NAME_EXP",
[2] = "KDC_ERR_SERVICE_EXP",
[3] = "KDC_ERR_BAD_PVNO",
[4] = "KDC_ERR_C_OLD_MAST_KVNO",
[5] = "KDC_ERR_S_OLD_MAST_KVNO",
[6] = "KDC_ERR_C_PRINCIPAL_UNKNOWN",
[7] = "KDC_ERR_S_PRINCIPAL_UNKNOWN",
[8] = "KDC_ERR_PRINCIPAL_NOT_UNIQUE",
[9] = "KDC_ERR_NULL_KEY",
[10] = "KDC_ERR_CANNOT_POSTDATE",
[11] = "KDC_ERR_NEVER_VALID",
[12] = "KDC_ERR_POLICY",
[13] = "KDC_ERR_BADOPTION",
[14] = "KDC_ERR_ETYPE_NOSUPP",
[15] = "KDC_ERR_SUMTYPE_NOSUPP",
[16] = "KDC_ERR_PADATA_TYPE_NOSUPP",
[17] = "KDC_ERR_TRTYPE_NOSUPP",
[18] = "KDC_ERR_CLIENT_REVOKED",
[19] = "KDC_ERR_SERVICE_REVOKED",
[20] = "KDC_ERR_TGT_REVOKED",
[21] = "KDC_ERR_CLIENT_NOTYET",
[22] = "KDC_ERR_SERVICE_NOTYET",
[23] = "KDC_ERR_KEY_EXPIRED",
[24] = "KDC_ERR_PREAUTH_FAILED",
[25] = "KDC_ERR_PREAUTH_REQUIRED",
[26] = "KDC_ERR_SERVER_NOMATCH",
[27] = "KDC_ERR_MUST_USE_USER2USER",
[28] = "KDC_ERR_PATH_NOT_ACCEPTED",
[29] = "KDC_ERR_SVC_UNAVAILABLE",
[31] = "KRB_AP_ERR_BAD_INTEGRITY",
[32] = "KRB_AP_ERR_TKT_EXPIRED",
[33] = "KRB_AP_ERR_TKT_NYV",
[34] = "KRB_AP_ERR_REPEAT",
[35] = "KRB_AP_ERR_NOT_US",
[36] = "KRB_AP_ERR_BADMATCH",
[37] = "KRB_AP_ERR_SKEW",
[38] = "KRB_AP_ERR_BADADDR",
[39] = "KRB_AP_ERR_BADVERSION",
[40] = "KRB_AP_ERR_MSG_TYPE",
[41] = "KRB_AP_ERR_MODIFIED",
[42] = "KRB_AP_ERR_BADORDER",
[44] = "KRB_AP_ERR_BADKEYVER",
[45] = "KRB_AP_ERR_NOKEY",
[46] = "KRB_AP_ERR_MUT_FAIL",
[47] = "KRB_AP_ERR_BADDIRECTION",
[48] = "KRB_AP_ERR_METHOD",
[49] = "KRB_AP_ERR_BADSEQ",
[50] = "KRB_AP_ERR_INAPP_CKSUM",
[51] = "KRB_AP_PATH_NOT_ACCEPTED",
[52] = "KRB_ERR_RESPONSE_TOO_BIG",
[60] = "KRB_ERR_GENERIC",
[61] = "KRB_ERR_FIELD_TOOLONG",
[62] = "KDC_ERROR_CLIENT_NOT_TRUSTED",
[63] = "KDC_ERROR_KDC_NOT_TRUSTED",
[64] = "KDC_ERROR_INVALID_SIG",
[65] = "KDC_ERR_KEY_TOO_WEAK",
[66] = "KDC_ERR_CERTIFICATE_MISMATCH",
[67] = "KRB_AP_ERR_NO_TGT",
[68] = "KDC_ERR_WRONG_REALM",
[69] = "KRB_AP_ERR_USER_TO_USER_REQUIRED",
[70] = "KDC_ERR_CANT_VERIFY_CERTIFICATE",
[71] = "KDC_ERR_INVALID_CERTIFICATE",
[72] = "KDC_ERR_REVOKED_CERTIFICATE",
[73] = "KDC_ERR_REVOCATION_STATUS_UNKNOWN",
[74] = "KDC_ERR_REVOCATION_STATUS_UNAVAILABLE",
[75] = "KDC_ERR_CLIENT_NAME_MISMATCH",
[76] = "KDC_ERR_KDC_NAME_MISMATCH",
};
const cipher_name: table[count] of string = {
[1] = "des-cbc-crc",
[2] = "des-cbc-md4",
[3] = "des-cbc-md5",
[5] = "des3-cbc-md5",
[7] = "des3-cbc-sha1",
[9] = "dsaWithSHA1-CmsOID",
[10] = "md5WithRSAEncryption-CmsOID",
[11] = "sha1WithRSAEncryption-CmsOID",
[12] = "rc2CBC-EnvOID",
[13] = "rsaEncryption-EnvOID",
[14] = "rsaES-OAEP-ENV-OID",
[15] = "des-ede3-cbc-Env-OID",
[16] = "des3-cbc-sha1-kd",
[17] = "aes128-cts-hmac-sha1-96",
[18] = "aes256-cts-hmac-sha1-96",
[23] = "rc4-hmac",
[24] = "rc4-hmac-exp",
[25] = "camellia128-cts-cmac",
[26] = "camellia256-cts-cmac",
[65] = "subkey-keymaterial",
};
}

View file

@ -0,0 +1,26 @@
# This is the ASN.1 encoded version and message type headers
signature dpd_krb_udp_requests {
ip-proto == udp
payload /(\x6a|\x6c).{1,4}\x30.{1,4}\xa1\x03\x02\x01\x05\xa2\x03\x02\x01/
enable "krb"
}
signature dpd_krb_udp_replies {
ip-proto == udp
payload /(\x6b|\x6d|\x7e).{1,4}\x30.{1,4}\xa0\x03\x02\x01\x05\xa1\x03\x02\x01/
enable "krb"
}
signature dpd_krb_tcp_requests {
ip-proto == tcp
payload /.{4}(\x6a|\x6c).{1,4}\x30.{1,4}\xa1\x03\x02\x01\x05\xa2\x03\x02\x01/
enable "krb_tcp"
}
signature dpd_krb_tcp_replies {
ip-proto == tcp
payload /.{4}(\x6b|\x6d|\x7e).{1,4}\x30.{1,4}\xa0\x03\x02\x01\x05\xa1\x03\x02\x01/
enable "krb_tcp"
}

View file

@ -0,0 +1,142 @@
@load ./main
@load base/utils/conn-ids
@load base/frameworks/files
@load base/files/x509
module KRB;
export {
redef record Info += {
# Client certificate
client_cert: Files::Info &optional;
# Subject of client certificate, if any
client_cert_subject: string &log &optional;
# File unique ID of client cert, if any
client_cert_fuid: string &log &optional;
# Server certificate
server_cert: Files::Info &optional;
# Subject of server certificate, if any
server_cert_subject: string &log &optional;
# File unique ID of server cert, if any
server_cert_fuid: string &log &optional;
};
## Default file handle provider for KRB.
global get_file_handle: function(c: connection, is_orig: bool): string;
## Default file describer for KRB.
global describe_file: function(f: fa_file): string;
}
function get_file_handle(c: connection, is_orig: bool): string
{
# Unused. File handles are generated in the analyzer.
return "";
}
function describe_file(f: fa_file): string
{
if ( f$source != "KRB_TCP" && f$source != "KRB" )
return "";
if ( ! f?$info || ! f$info?$x509 || ! f$info$x509?$certificate )
return "";
# It is difficult to reliably describe a certificate - especially since
# we do not know when this function is called (hence, if the data structures
# are already populated).
#
# Just return a bit of our connection information and hope that that is good enough.
for ( cid in f$conns )
{
if ( f$conns[cid]?$krb )
{
local c = f$conns[cid];
return cat(c$id$resp_h, ":", c$id$resp_p);
}
}
return cat("Serial: ", f$info$x509$certificate$serial, " Subject: ",
f$info$x509$certificate$subject, " Issuer: ",
f$info$x509$certificate$issuer);
}
event bro_init() &priority=5
{
Files::register_protocol(Analyzer::ANALYZER_KRB_TCP,
[$get_file_handle = KRB::get_file_handle,
$describe = KRB::describe_file]);
Files::register_protocol(Analyzer::ANALYZER_KRB,
[$get_file_handle = KRB::get_file_handle,
$describe = KRB::describe_file]);
}
event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priority=5
{
if ( f$source != "KRB_TCP" && f$source != "KRB" )
return;
local info: Info;
if ( ! c?$krb )
{
info$ts = network_time();
info$uid = c$uid;
info$id = c$id;
}
else
info = c$krb;
if ( is_orig )
{
info$client_cert = f$info;
info$client_cert_fuid = f$id;
}
else
{
info$server_cert = f$info;
info$server_cert_fuid = f$id;
}
c$krb = info;
Files::add_analyzer(f, Files::ANALYZER_X509);
# Always calculate hashes. They are not necessary for base scripts
# but very useful for identification, and required for policy scripts
Files::add_analyzer(f, Files::ANALYZER_MD5);
Files::add_analyzer(f, Files::ANALYZER_SHA1);
}
function fill_in_subjects(c: connection)
{
if ( !c?$krb )
return;
if ( c$krb?$client_cert && c$krb$client_cert?$x509 && c$krb$client_cert$x509?$certificate )
c$krb$client_cert_subject = c$krb$client_cert$x509$certificate$subject;
if ( c$krb?$server_cert && c$krb$server_cert?$x509 && c$krb$server_cert$x509?$certificate )
c$krb$server_cert_subject = c$krb$server_cert$x509$certificate$subject;
}
event krb_error(c: connection, msg: Error_Msg)
{
fill_in_subjects(c);
}
event krb_as_response(c: connection, msg: KDC_Response)
{
fill_in_subjects(c);
}
event krb_tgs_response(c: connection, msg: KDC_Response)
{
fill_in_subjects(c);
}
event connection_state_remove(c: connection)
{
fill_in_subjects(c);
}

View file

@ -0,0 +1,250 @@
##! Implements base functionality for KRB analysis. Generates the krb.log file.
module KRB;
@load ./consts
export {
redef enum Log::ID += { LOG };
type Info: record {
## Timestamp for when the event happened.
ts: time &log;
## Unique ID for the connection.
uid: string &log;
## The connection's 4-tuple of endpoint addresses/ports.
id: conn_id &log;
## Request type - Authentication Service ("AS") or
## Ticket Granting Service ("TGS")
request_type: string &log &optional;
## Client
client: string &log &optional;
## Service
service: string &log;
## Request result
success: bool &log &optional;
## Error code
error_code: count &optional;
## Error message
error_msg: string &log &optional;
## Ticket valid from
from: time &log &optional;
## Ticket valid till
till: time &log &optional;
## Ticket encryption type
cipher: string &log &optional;
## Forwardable ticket requested
forwardable: bool &log &optional;
## Renewable ticket requested
renewable: bool &log &optional;
## We've already logged this
logged: bool &default=F;
};
## The server response error texts which are *not* logged.
const ignored_errors: set[string] = {
# This will significantly increase the noisiness of the log.
# However, one attack is to iterate over principals, looking
# for ones that don't require preauth, and then performn
# an offline attack on that ticket. To detect that attack,
# log NEEDED_PREAUTH.
"NEEDED_PREAUTH",
# This is a more specific version of NEEDED_PREAUTH that's used
# by Windows AD Kerberos.
"Need to use PA-ENC-TIMESTAMP/PA-PK-AS-REQ",
} &redef;
## Event that can be handled to access the KRB record as it is sent on
## to the logging framework.
global log_krb: event(rec: Info);
}
redef record connection += {
krb: Info &optional;
};
const tcp_ports = { 88/tcp };
const udp_ports = { 88/udp };
redef likely_server_ports += { tcp_ports, udp_ports };
event bro_init() &priority=5
{
Analyzer::register_for_ports(Analyzer::ANALYZER_KRB, udp_ports);
Analyzer::register_for_ports(Analyzer::ANALYZER_KRB_TCP, tcp_ports);
Log::create_stream(KRB::LOG, [$columns=Info, $ev=log_krb, $path="kerberos"]);
}
event krb_error(c: connection, msg: Error_Msg) &priority=5
{
local info: Info;
if ( msg?$error_text && msg$error_text in ignored_errors )
{
if ( c?$krb ) delete c$krb;
return;
}
if ( c?$krb && c$krb$logged )
return;
if ( c?$krb )
info = c$krb;
if ( ! info?$ts )
{
info$ts = network_time();
info$uid = c$uid;
info$id = c$id;
}
if ( ! info?$client && ( msg?$client_name || msg?$client_realm ) )
info$client = fmt("%s%s", msg?$client_name ? msg$client_name + "/" : "",
msg?$client_realm ? msg$client_realm : "");
info$service = msg$service_name;
info$success = F;
info$error_code = msg$error_code;
if ( msg?$error_text ) info$error_msg = msg$error_text;
else if ( msg$error_code in error_msg ) info$error_msg = error_msg[msg$error_code];
c$krb = info;
}
event krb_error(c: connection, msg: Error_Msg) &priority=-5
{
if ( c?$krb )
{
Log::write(KRB::LOG, c$krb);
c$krb$logged = T;
}
}
event krb_as_request(c: connection, msg: KDC_Request) &priority=5
{
if ( c?$krb && c$krb$logged )
return;
local info: Info;
if ( !c?$krb )
{
info$ts = network_time();
info$uid = c$uid;
info$id = c$id;
}
else
info = c$krb;
info$request_type = "AS";
info$client = fmt("%s/%s", msg$client_name, msg$service_realm);
info$service = msg$service_name;
if ( msg?$from )
info$from = msg$from;
info$till = msg$till;
info$forwardable = msg$kdc_options$forwardable;
info$renewable = msg$kdc_options$renewable;
c$krb = info;
}
event krb_tgs_request(c: connection, msg: KDC_Request) &priority=5
{
if ( c?$krb && c$krb$logged )
return;
local info: Info;
info$ts = network_time();
info$uid = c$uid;
info$id = c$id;
info$request_type = "TGS";
info$service = msg$service_name;
if ( msg?$from ) info$from = msg$from;
info$till = msg$till;
info$forwardable = msg$kdc_options$forwardable;
info$renewable = msg$kdc_options$renewable;
c$krb = info;
}
event krb_as_response(c: connection, msg: KDC_Response) &priority=5
{
local info: Info;
if ( c?$krb && c$krb$logged )
return;
if ( c?$krb )
info = c$krb;
if ( ! info?$ts )
{
info$ts = network_time();
info$uid = c$uid;
info$id = c$id;
}
if ( ! info?$client )
info$client = fmt("%s/%s", msg$client_name, msg$client_realm);
info$service = msg$ticket$service_name;
info$cipher = cipher_name[msg$ticket$cipher];
info$success = T;
c$krb = info;
}
event krb_as_response(c: connection, msg: KDC_Response) &priority=-5
{
Log::write(KRB::LOG, c$krb);
c$krb$logged = T;
}
event krb_tgs_response(c: connection, msg: KDC_Response) &priority=5
{
local info: Info;
if ( c?$krb && c$krb$logged )
return;
if ( c?$krb )
info = c$krb;
if ( ! info?$ts )
{
info$ts = network_time();
info$uid = c$uid;
info$id = c$id;
}
if ( ! info?$client )
info$client = fmt("%s/%s", msg$client_name, msg$client_realm);
info$service = msg$ticket$service_name;
info$cipher = cipher_name[msg$ticket$cipher];
info$success = T;
c$krb = info;
}
event krb_tgs_response(c: connection, msg: KDC_Response) &priority=-5
{
Log::write(KRB::LOG, c$krb);
c$krb$logged = T;
}
event connection_state_remove(c: connection) &priority=-5
{
if ( c?$krb && ! c$krb$logged )
Log::write(KRB::LOG, c$krb);
}

View file

@ -0,0 +1,3 @@
@load ./main
@load-sigs ./dpd.sig

View file

@ -0,0 +1,19 @@
signature dpd_sip_udp_req {
ip-proto == udp
payload /.* SIP\/[0-9]\.[0-9]\x0d\x0a/
enable "sip"
}
signature dpd_sip_udp_resp {
ip-proto == udp
payload /^ ?SIP\/[0-9]\.[0-9](\x0d\x0a| [0-9][0-9][0-9] )/
enable "sip"
}
# We don't support SIP-over-TCP yet.
#
# signature dpd_sip_tcp {
# ip-proto == tcp
# payload /^( SIP\/[0-9]\.[0-9]\x0d\x0a|SIP\/[0-9]\.[0-9] [0-9][0-9][0-9] )/
# enable "sip_tcp"
# }

View file

@ -0,0 +1,272 @@
##! Implements base functionality for SIP analysis. The logging model is
##! to log request/response pairs and all relevant metadata together in
##! a single record.
@load base/utils/numbers
@load base/utils/files
module SIP;
export {
redef enum Log::ID += { LOG };
type Info: record {
## Timestamp for when the request happened.
ts: time &log;
## Unique ID for the connection.
uid: string &log;
## The connection's 4-tuple of endpoint addresses/ports.
id: conn_id &log;
## Represents the pipelined depth into the connection of this
## request/response transaction.
trans_depth: count &log;
## Verb used in the SIP request (INVITE, REGISTER etc.).
method: string &log &optional;
## URI used in the request.
uri: string &log &optional;
## Contents of the Date: header from the client
date: string &log &optional;
## Contents of the request From: header
## Note: The tag= value that's usually appended to the sender
## is stripped off and not logged.
request_from: string &log &optional;
## Contents of the To: header
request_to: string &log &optional;
## Contents of the response From: header
## Note: The ``tag=`` value that's usually appended to the sender
## is stripped off and not logged.
response_from: string &log &optional;
## Contents of the response To: header
response_to: string &log &optional;
## Contents of the Reply-To: header
reply_to: string &log &optional;
## Contents of the Call-ID: header from the client
call_id: string &log &optional;
## Contents of the CSeq: header from the client
seq: string &log &optional;
## Contents of the Subject: header from the client
subject: string &log &optional;
## The client message transmission path, as extracted from the headers.
request_path: vector of string &log &optional;
## The server message transmission path, as extracted from the headers.
response_path: vector of string &log &optional;
## Contents of the User-Agent: header from the client
user_agent: string &log &optional;
## Status code returned by the server.
status_code: count &log &optional;
## Status message returned by the server.
status_msg: string &log &optional;
## Contents of the Warning: header
warning: string &log &optional;
## Contents of the Content-Length: header from the client
request_body_len: string &log &optional;
## Contents of the Content-Length: header from the server
response_body_len: string &log &optional;
## Contents of the Content-Type: header from the server
content_type: string &log &optional;
};
type State: record {
## Pending requests.
pending: table[count] of Info;
## Current request in the pending queue.
current_request: count &default=0;
## Current response in the pending queue.
current_response: count &default=0;
};
## A list of SIP methods. Other methods will generate a weird. Note
## that the SIP analyzer will only accept methods consisting solely
## of letters ``[A-Za-z]``.
const sip_methods: set[string] = {
"REGISTER", "INVITE", "ACK", "CANCEL", "BYE", "OPTIONS"
} &redef;
## Event that can be handled to access the SIP record as it is sent on
## to the logging framework.
global log_sip: event(rec: Info);
}
# Add the sip state tracking fields to the connection record.
redef record connection += {
sip: Info &optional;
sip_state: State &optional;
};
const ports = { 5060/udp };
redef likely_server_ports += { ports };
event bro_init() &priority=5
{
Log::create_stream(SIP::LOG, [$columns=Info, $ev=log_sip, $path="sip"]);
Analyzer::register_for_ports(Analyzer::ANALYZER_SIP, ports);
}
function new_sip_session(c: connection): Info
{
local tmp: Info;
tmp$ts=network_time();
tmp$uid=c$uid;
tmp$id=c$id;
# $current_request is set prior to the Info record creation so we
# can use the value directly here.
tmp$trans_depth = c$sip_state$current_request;
tmp$request_path = vector();
tmp$response_path = vector();
return tmp;
}
function set_state(c: connection, is_request: bool)
{
if ( ! c?$sip_state )
{
local s: State;
c$sip_state = s;
}
# These deal with new requests and responses.
if ( is_request && c$sip_state$current_request !in c$sip_state$pending )
c$sip_state$pending[c$sip_state$current_request] = new_sip_session(c);
if ( ! is_request && c$sip_state$current_response !in c$sip_state$pending )
c$sip_state$pending[c$sip_state$current_response] = new_sip_session(c);
if ( is_request )
c$sip = c$sip_state$pending[c$sip_state$current_request];
else
c$sip = c$sip_state$pending[c$sip_state$current_response];
if ( is_request )
{
if ( c$sip_state$current_request !in c$sip_state$pending )
c$sip_state$pending[c$sip_state$current_request] = new_sip_session(c);
c$sip = c$sip_state$pending[c$sip_state$current_request];
}
else
{
if ( c$sip_state$current_response !in c$sip_state$pending )
c$sip_state$pending[c$sip_state$current_response] = new_sip_session(c);
c$sip = c$sip_state$pending[c$sip_state$current_response];
}
}
function flush_pending(c: connection)
{
# Flush all pending but incomplete request/response pairs.
if ( c?$sip_state )
{
for ( r in c$sip_state$pending )
{
# We don't use pending elements at index 0.
if ( r == 0 ) next;
Log::write(SIP::LOG, c$sip_state$pending[r]);
}
}
}
event sip_request(c: connection, method: string, original_URI: string, version: string) &priority=5
{
set_state(c, T);
c$sip$method = method;
c$sip$uri = original_URI;
if ( method !in sip_methods )
event conn_weird("unknown_SIP_method", c, method);
}
event sip_reply(c: connection, version: string, code: count, reason: string) &priority=5
{
set_state(c, F);
if ( c$sip_state$current_response !in c$sip_state$pending &&
(code < 100 && 200 <= code) )
++c$sip_state$current_response;
c$sip$status_code = code;
c$sip$status_msg = reason;
}
event sip_header(c: connection, is_request: bool, name: string, value: string) &priority=5
{
if ( ! c?$sip_state )
{
local s: State;
c$sip_state = s;
}
if ( is_request ) # from client
{
if ( c$sip_state$current_request !in c$sip_state$pending )
++c$sip_state$current_request;
set_state(c, is_request);
if ( name == "CALL-ID" ) c$sip$call_id = value;
else if ( name == "CONTENT-LENGTH" || name == "L" ) c$sip$request_body_len = value;
else if ( name == "CSEQ" ) c$sip$seq = value;
else if ( name == "DATE" ) c$sip$date = value;
else if ( name == "FROM" || name == "F" ) c$sip$request_from = split_string1(value, /;[ ]?tag=/)[0];
else if ( name == "REPLY-TO" ) c$sip$reply_to = value;
else if ( name == "SUBJECT" || name == "S" ) c$sip$subject = value;
else if ( name == "TO" || name == "T" ) c$sip$request_to = value;
else if ( name == "USER-AGENT" ) c$sip$user_agent = value;
else if ( name == "VIA" || name == "V" ) c$sip$request_path[|c$sip$request_path|] = split_string1(value, /;[ ]?branch/)[0];
c$sip_state$pending[c$sip_state$current_request] = c$sip;
}
else # from server
{
if ( c$sip_state$current_response !in c$sip_state$pending )
++c$sip_state$current_response;
set_state(c, is_request);
if ( name == "CONTENT-LENGTH" || name == "L" ) c$sip$response_body_len = value;
else if ( name == "CONTENT-TYPE" || name == "C" ) c$sip$content_type = value;
else if ( name == "WARNING" ) c$sip$warning = value;
else if ( name == "FROM" || name == "F" ) c$sip$response_from = split_string1(value, /;[ ]?tag=/)[0];
else if ( name == "TO" || name == "T" ) c$sip$response_to = value;
else if ( name == "VIA" || name == "V" ) c$sip$response_path[|c$sip$response_path|] = split_string1(value, /;[ ]?branch/)[0];
c$sip_state$pending[c$sip_state$current_response] = c$sip;
}
}
event sip_end_entity(c: connection, is_request: bool) &priority = 5
{
set_state(c, is_request);
}
event sip_end_entity(c: connection, is_request: bool) &priority = -5
{
# The reply body is done so we're ready to log.
if ( ! is_request )
{
Log::write(SIP::LOG, c$sip);
if ( c$sip$status_code < 100 || 200 <= c$sip$status_code )
delete c$sip_state$pending[c$sip_state$current_response];
if ( ! c$sip?$method || ( c$sip$method == "BYE" &&
c$sip$status_code >= 200 && c$sip$status_code < 300 ) )
{
flush_pending(c);
delete c$sip;
delete c$sip_state;
}
}
}
event connection_state_remove(c: connection) &priority=-5
{
if ( c?$sip_state )
{
for ( r in c$sip_state$pending )
{
Log::write(SIP::LOG, c$sip_state$pending[r]);
}
}
}

View file

@ -93,6 +93,10 @@ function set_session(c: connection)
info$ts = network_time();
info$uid = c$uid;
info$id = c$id;
# If both hosts are local or non-local, we can't reliably set a direction.
if ( Site::is_local_addr(c$id$orig_h) != Site::is_local_addr(c$id$resp_h) )
info$direction = Site::is_local_addr(c$id$orig_h) ? OUTBOUND: INBOUND;
c$ssh = info;
}
}
@ -114,7 +118,7 @@ event ssh_client_version(c: connection, version: string)
c$ssh$version = 2;
}
event ssh_auth_successful(c: connection, auth_method_none: bool)
event ssh_auth_successful(c: connection, auth_method_none: bool) &priority=5
{
# TODO - what to do here?
if ( !c?$ssh || ( c$ssh?$auth_success && c$ssh$auth_success ) )
@ -142,7 +146,7 @@ event ssh_auth_successful(c: connection, auth_method_none: bool) &priority=-5
}
}
event ssh_auth_failed(c: connection)
event ssh_auth_failed(c: connection) &priority=5
{
if ( !c?$ssh || ( c$ssh?$auth_success && !c$ssh$auth_success ) )
return;

View file

@ -32,6 +32,9 @@ function get_location(c: connection): geo_location
event ssh_auth_successful(c: connection, auth_method_none: bool) &priority=3
{
if ( ! c$ssh?$direction )
return;
# Add the location data to the SSH record.
c$ssh$remote_location = get_location(c);
@ -47,6 +50,9 @@ event ssh_auth_successful(c: connection, auth_method_none: bool) &priority=3
event ssh_auth_failed(c: connection) &priority=3
{
if ( ! c$ssh?$direction )
return;
# Add the location data to the SSH record.
c$ssh$remote_location = get_location(c);
}

View file

@ -194,22 +194,7 @@ char* BroString::Render(int format, int* len) const
for ( int i = 0; i < n; ++i )
{
if ( b[i] == '\0' && (format & ESC_NULL) )
{
*sp++ = '\\'; *sp++ = '0';
}
else if ( b[i] == '\x7f' && (format & ESC_DEL) )
{
*sp++ = '^'; *sp++ = '?';
}
else if ( b[i] <= 26 && (format & ESC_LOW) )
{
*sp++ = '^'; *sp++ = b[i] + 'A' - 1;
}
else if ( b[i] == '\\' && (format & ESC_ESC) )
if ( b[i] == '\\' && (format & ESC_ESC) )
{
*sp++ = '\\'; *sp++ = '\\';
}

View file

@ -75,21 +75,17 @@ public:
enum render_style {
ESC_NONE = 0,
ESC_NULL = (1 << 0), // 0 -> "\0"
ESC_DEL = (1 << 1), // DEL -> "^?"
ESC_LOW = (1 << 2), // values <= 26 mapped into "^[A-Z]"
ESC_ESC = (1 << 3), // '\' -> "\\"
ESC_QUOT = (1 << 4), // '"' -> "\"", ''' -> "\'"
ESC_HEX = (1 << 5), // Not in [32, 126]? -> "%XX"
ESC_DOT = (1 << 6), // Not in [32, 126]? -> "."
ESC_ESC = (1 << 1), // '\' -> "\\"
ESC_QUOT = (1 << 2), // '"' -> "\"", ''' -> "\'"
ESC_HEX = (1 << 3), // Not in [32, 126]? -> "\xXX"
ESC_DOT = (1 << 4), // Not in [32, 126]? -> "."
// For serialization: '<string len> <string>'
ESC_SER = (1 << 7),
};
static const int EXPANDED_STRING = // the original style
ESC_NULL | ESC_DEL | ESC_LOW | ESC_HEX;
ESC_HEX;
static const int BRO_STRING_LITERAL = // as in a Bro string literal
ESC_ESC | ESC_QUOT | ESC_HEX;

View file

@ -375,17 +375,15 @@ RecordVal* Connection::BuildConnVal()
conn_val->Assign(2, resp_endp);
// 3 and 4 are set below.
conn_val->Assign(5, new TableVal(string_set)); // service
conn_val->Assign(6, new StringVal("")); // addl
conn_val->Assign(7, new Val(0, TYPE_COUNT)); // hot
conn_val->Assign(8, new StringVal("")); // history
conn_val->Assign(6, new StringVal("")); // history
if ( ! uid )
uid.Set(bits_per_uid);
conn_val->Assign(9, new StringVal(uid.Base62("C").c_str()));
conn_val->Assign(7, new StringVal(uid.Base62("C").c_str()));
if ( encapsulation && encapsulation->Depth() > 0 )
conn_val->Assign(10, encapsulation->GetVectorVal());
conn_val->Assign(8, encapsulation->GetVectorVal());
}
if ( root_analyzer )
@ -393,7 +391,7 @@ RecordVal* Connection::BuildConnVal()
conn_val->Assign(3, new Val(start_time, TYPE_TIME)); // ###
conn_val->Assign(4, new Val(last_time - start_time, TYPE_INTERVAL));
conn_val->Assign(8, new StringVal(history.c_str()));
conn_val->Assign(6, new StringVal(history.c_str()));
conn_val->SetOrigin(this);

View file

@ -181,13 +181,7 @@ void ODesc::AddBytes(const BroString* s)
AddBytes(reinterpret_cast<const char*>(s->Bytes()), s->Len());
else
{
int render_style = BroString::EXPANDED_STRING;
if ( Style() == ALTERNATIVE_STYLE )
// Only change NULs, since we can't in any case
// cope with them.
render_style = BroString::ESC_NULL;
const char* str = s->Render(render_style);
const char* str = s->Render(BroString::EXPANDED_STRING);
Add(str);
delete [] str;
}
@ -256,7 +250,7 @@ pair<const char*, size_t> ODesc::FirstEscapeLoc(const char* bytes, size_t n)
for ( size_t i = 0; i < n; ++i )
{
if ( ! isprint(bytes[i]) )
if ( ! isprint(bytes[i]) || bytes[i] == '\\' )
return escape_pos(bytes + i, 1);
size_t len = StartsWithEscapeSequence(bytes + i, bytes + n);

View file

@ -17,7 +17,6 @@ typedef enum {
typedef enum {
STANDARD_STYLE,
ALTERNATIVE_STYLE,
RAW_STYLE,
} desc_style;

View file

@ -249,18 +249,6 @@ NameExpr::~NameExpr()
Unref(id);
}
Expr* NameExpr::Simplify(SimplifyType simp_type)
{
if ( simp_type != SIMPLIFY_LHS && id->IsConst() )
{
Val* v = Eval(0);
if ( v )
return new ConstExpr(v);
}
return this;
}
Val* NameExpr::Eval(Frame* f) const
{
Val* v;
@ -410,11 +398,6 @@ void ConstExpr::ExprDescribe(ODesc* d) const
val->Describe(d);
}
Expr* ConstExpr::Simplify(SimplifyType /* simp_type */)
{
return this;
}
Val* ConstExpr::Eval(Frame* /* f */) const
{
return Value()->Ref();
@ -457,16 +440,6 @@ UnaryExpr::~UnaryExpr()
Unref(op);
}
Expr* UnaryExpr::Simplify(SimplifyType simp_type)
{
if ( IsError() )
return this;
op = simplify_expr(op, simp_type);
Canonicize();
return DoSimplify();
}
Val* UnaryExpr::Eval(Frame* f) const
{
if ( IsError() )
@ -516,11 +489,6 @@ TraversalCode UnaryExpr::Traverse(TraversalCallback* cb) const
HANDLE_TC_EXPR_POST(tc);
}
Expr* UnaryExpr::DoSimplify()
{
return this;
}
Val* UnaryExpr::Fold(Val* v) const
{
return v->Ref();
@ -573,19 +541,6 @@ BinaryExpr::~BinaryExpr()
Unref(op2);
}
Expr* BinaryExpr::Simplify(SimplifyType /* simp_type */)
{
if ( IsError() )
return this;
SimplifyOps();
if ( BothConst() )
return new ConstExpr(Fold(op1->ExprVal(), op2->ExprVal()));
else
return DoSimplify();
}
Val* BinaryExpr::Eval(Frame* f) const
{
if ( IsError() )
@ -687,11 +642,6 @@ TraversalCode BinaryExpr::Traverse(TraversalCallback* cb) const
HANDLE_TC_EXPR_POST(tc);
}
Expr* BinaryExpr::DoSimplify()
{
return this;
}
void BinaryExpr::ExprDescribe(ODesc* d) const
{
op1->Describe(d);
@ -703,13 +653,6 @@ void BinaryExpr::ExprDescribe(ODesc* d) const
op2->Describe(d);
}
void BinaryExpr::SimplifyOps()
{
op1 = simplify_expr(op1, SIMPLIFY_GENERAL);
op2 = simplify_expr(op2, SIMPLIFY_GENERAL);
Canonicize();
}
Val* BinaryExpr::Fold(Val* v1, Val* v2) const
{
InternalTypeTag it = v1->Type()->InternalType();
@ -1147,21 +1090,6 @@ NotExpr::NotExpr(Expr* arg_op) : UnaryExpr(EXPR_NOT, arg_op)
SetType(base_type(TYPE_BOOL));
}
Expr* NotExpr::DoSimplify()
{
op = simplify_expr(op, SIMPLIFY_GENERAL);
Canonicize();
if ( op->Tag() == EXPR_NOT )
// !!x == x
return ((NotExpr*) op)->Op()->Ref();
if ( op->IsConst() )
return new ConstExpr(Fold(op->ExprVal()));
return this;
}
Val* NotExpr::Fold(Val* v) const
{
return new Val(! v->InternalInt(), type->Tag());
@ -1207,22 +1135,6 @@ PosExpr::PosExpr(Expr* arg_op) : UnaryExpr(EXPR_POSITIVE, arg_op)
SetType(base_result_type);
}
Expr* PosExpr::DoSimplify()
{
op = simplify_expr(op, SIMPLIFY_GENERAL);
Canonicize();
TypeTag t = op->Type()->Tag();
if ( t == TYPE_DOUBLE || t == TYPE_INTERVAL || t == TYPE_INT )
return op->Ref();
if ( op->IsConst() && ! is_vector(op->ExprVal()) )
return new ConstExpr(Fold(op->ExprVal()));
return this;
}
Val* PosExpr::Fold(Val* v) const
{
TypeTag t = v->Type()->Tag();
@ -1273,27 +1185,6 @@ NegExpr::NegExpr(Expr* arg_op) : UnaryExpr(EXPR_NEGATE, arg_op)
SetType(base_result_type);
}
Expr* NegExpr::DoSimplify()
{
op = simplify_expr(op, SIMPLIFY_GENERAL);
Canonicize();
if ( op->Tag() == EXPR_NEGATE )
// -(-x) == x
return ((NegExpr*) op)->Op()->Ref();
if ( op->IsConst() && ! is_vector(op->ExprVal()) )
return new ConstExpr(Fold(op->ExprVal()));
if ( op->Tag() == EXPR_SUB )
{ // -(a-b) == b-a
SubExpr* s = (SubExpr*) op;
return new SubExpr(s->Op2()->Ref(), s->Op1()->Ref());
}
return this;
}
Val* NegExpr::Fold(Val* v) const
{
if ( v->Type()->Tag() == TYPE_DOUBLE )
@ -1396,24 +1287,6 @@ AddExpr::AddExpr(Expr* arg_op1, Expr* arg_op2)
}
}
Expr* AddExpr::DoSimplify()
{
// If there's a constant, then it's in op1, since Canonicize()
// makes sure of that.
if ( op1->IsZero() )
return op2->Ref();
else if ( op1->Tag() == EXPR_NEGATE )
// (-a)+b = b-a
return new AddExpr(op2->Ref(), ((NegExpr*) op1)->Op()->Ref());
else if ( op2->Tag() == EXPR_NEGATE )
// a+(-b) == a-b
return new SubExpr(op1->Ref(), ((NegExpr*) op2)->Op()->Ref());
return this;
}
void AddExpr::Canonicize()
{
if ( expr_greater(op2, op1) ||
@ -1532,21 +1405,6 @@ SubExpr::SubExpr(Expr* arg_op1, Expr* arg_op2)
}
}
Expr* SubExpr::DoSimplify()
{
if ( op1->IsZero() )
return new NegExpr(op2->Ref());
else if ( op2->IsZero() )
return op1->Ref();
else if ( op2->Tag() == EXPR_NEGATE )
// a-(-b) = a+b
return new AddExpr(op1->Ref(), ((NegExpr*) op2)->Op()->Ref());
return this;
}
IMPLEMENT_SERIAL(SubExpr, SER_SUB_EXPR);
bool SubExpr::DoSerialize(SerialInfo* info) const
@ -1648,27 +1506,6 @@ TimesExpr::TimesExpr(Expr* arg_op1, Expr* arg_op2)
ExprError("requires arithmetic operands");
}
Expr* TimesExpr::DoSimplify()
{
// If there's a constant, then it's in op1, since Canonicize()
// makes sure of that.
if ( op1->IsConst() )
{
if ( op1->IsZero() )
{
if ( IsVector(op2->Type()->Tag()) )
return this;
else
return make_zero(type);
}
else if ( op1->IsOne() )
return op2->Ref();
}
return this;
}
void TimesExpr::Canonicize()
{
if ( expr_greater(op2, op1) || op2->Type()->Tag() == TYPE_INTERVAL ||
@ -1741,31 +1578,6 @@ Val* DivideExpr::AddrFold(Val* v1, Val* v2) const
return new SubNetVal(v1->AsAddr(), mask);
}
Expr* DivideExpr::DoSimplify()
{
if ( IsError() )
return this;
if ( op1->Type()->Tag() == TYPE_ADDR )
return this;
if ( is_vector(op1) || is_vector(op2) )
return this;
if ( op2->IsConst() )
{
if ( op2->IsOne() )
return op1->Ref();
else if ( op2->IsZero() )
Error("zero divisor");
}
else if ( same_expr(op1, op2) )
return make_one(type);
return this;
}
IMPLEMENT_SERIAL(DivideExpr, SER_DIVIDE_EXPR);
bool DivideExpr::DoSerialize(SerialInfo* info) const
@ -1800,31 +1612,6 @@ ModExpr::ModExpr(Expr* arg_op1, Expr* arg_op2)
ExprError("requires integral operands");
}
Expr* ModExpr::DoSimplify()
{
if ( IsError() )
return this;
TypeTag bt1 = op1->Type()->Tag();
TypeTag bt2 = op2->Type()->Tag();
if ( IsVector(bt1) || IsVector(bt2) )
return this;
if ( op2->IsConst() )
{
if ( op2->IsOne() )
return make_zero(type);
else if ( op2->IsZero() )
Error("zero modulus");
}
else if ( same_expr(op1, op2) )
return make_zero(type);
return this;
}
IMPLEMENT_SERIAL(ModExpr, SER_MOD_EXPR);
bool ModExpr::DoSerialize(SerialInfo* info) const
@ -2011,37 +1798,6 @@ Val* BoolExpr::Eval(Frame* f) const
return result;
}
Expr* BoolExpr::DoSimplify()
{
if ( op1->IsConst() && ! is_vector(op1) )
{
if ( op1->IsZero() )
// F && x or F || x
return (tag == EXPR_AND) ? make_zero(type) : op2->Ref();
else
// T && x or T || x
return (tag == EXPR_AND) ? op2->Ref() : make_one(type);
}
else if ( op2->IsConst() && ! is_vector(op2) )
{
if ( op1->IsZero() )
// x && F or x || F
return (tag == EXPR_AND) ? make_zero(type) : op1->Ref();
else
// x && T or x || T
return (tag == EXPR_AND) ? op1->Ref() : make_one(type);
}
else if ( same_expr(op1, op2) )
{
Warn("redundant boolean operation");
return op1->Ref();
}
return this;
}
IMPLEMENT_SERIAL(BoolExpr, SER_BOOL_EXPR);
bool BoolExpr::DoSerialize(SerialInfo* info) const
@ -2128,22 +1884,6 @@ void EqExpr::Canonicize()
SwapOps();
}
Expr* EqExpr::DoSimplify()
{
if ( same_expr(op1, op2) && ! is_vector(op1) )
{
if ( ! optimize )
Warn("redundant comparison");
if ( tag == EXPR_EQ )
return make_one(type);
else
return make_zero(type);
}
return this;
}
Val* EqExpr::Fold(Val* v1, Val* v2) const
{
if ( op1->Type()->Tag() == TYPE_PATTERN )
@ -2207,22 +1947,6 @@ RelExpr::RelExpr(BroExprTag arg_tag, Expr* arg_op1, Expr* arg_op2)
ExprError("illegal comparison");
}
Expr* RelExpr::DoSimplify()
{
if ( same_expr(op1, op2) )
{
Warn("redundant comparison");
// Here we use the fact that the canonical form of
// a RelExpr only uses EXPR_LE or EXPR_LT.
if ( tag == EXPR_LE )
return make_one(type);
else
return make_zero(type);
}
return this;
}
void RelExpr::Canonicize()
{
if ( tag == EXPR_GT )
@ -2314,25 +2038,6 @@ CondExpr::~CondExpr()
Unref(op3);
}
Expr* CondExpr::Simplify(SimplifyType /* simp_type */)
{
op1 = simplify_expr(op1, SIMPLIFY_GENERAL);
op2 = simplify_expr(op2, SIMPLIFY_GENERAL);
op3 = simplify_expr(op3, SIMPLIFY_GENERAL);
if ( op1->IsConst() && ! is_vector(op1) )
{
Val* v = op1->ExprVal();
return (v->IsZero() ? op3 : op2)->Ref();
}
if ( op1->Tag() == EXPR_NOT )
return new CondExpr(((NotExpr*) op1)->Op()->Ref(),
op3->Ref(), op2->Ref());
return this;
}
Val* CondExpr::Eval(Frame* f) const
{
if ( ! is_vector(op1) )
@ -2684,13 +2389,6 @@ bool AssignExpr::TypeCheckArithmetics(TypeTag bt1, TypeTag bt2)
}
Expr* AssignExpr::Simplify(SimplifyType /* simp_type */)
{
op1 = simplify_expr(op1, SIMPLIFY_LHS);
op2 = simplify_expr(op2, SIMPLIFY_GENERAL);
return this;
}
Val* AssignExpr::Eval(Frame* f) const
{
if ( is_init )
@ -3006,13 +2704,6 @@ Expr* IndexExpr::MakeLvalue()
return new RefExpr(this);
}
Expr* IndexExpr::Simplify(SimplifyType simp_type)
{
op1 = simplify_expr(op1, simp_type);
op2 = simplify_expr(op2, SIMPLIFY_GENERAL);
return this;
}
Val* IndexExpr::Eval(Frame* f) const
{
Val* v1 = op1->Eval(f);
@ -3264,12 +2955,6 @@ Expr* FieldExpr::MakeLvalue()
return new RefExpr(this);
}
Expr* FieldExpr::Simplify(SimplifyType simp_type)
{
op = simplify_expr(op, simp_type);
return this;
}
int FieldExpr::CanDel() const
{
return td->FindAttr(ATTR_DEFAULT) || td->FindAttr(ATTR_OPTIONAL);
@ -3995,73 +3680,6 @@ ArithCoerceExpr::ArithCoerceExpr(Expr* arg_op, TypeTag t)
ExprError("bad coercion value");
}
Expr* ArithCoerceExpr::DoSimplify()
{
if ( is_vector(op) )
return this;
InternalTypeTag my_int = type->InternalType();
InternalTypeTag op_int = op->Type()->InternalType();
if ( my_int == TYPE_INTERNAL_UNSIGNED )
my_int = TYPE_INTERNAL_INT;
if ( op_int == TYPE_INTERNAL_UNSIGNED )
op_int = TYPE_INTERNAL_INT;
if ( my_int == op_int )
return op->Ref();
if ( op->IsConst() )
{
if ( my_int == TYPE_INTERNAL_INT )
{
if ( op_int != TYPE_INTERNAL_DOUBLE )
Internal("bad coercion in CoerceExpr::DoSimplify");
double d = op->ExprVal()->InternalDouble();
bro_int_t i = bro_int_t(d);
if ( i < 0 &&
type->InternalType() == TYPE_INTERNAL_UNSIGNED )
Warn("coercion produces negative count value");
if ( d != double(i) )
Warn("coercion loses precision");
return new ConstExpr(new Val(i, type->Tag()));
}
if ( my_int == TYPE_INTERNAL_DOUBLE )
{
if ( op_int == TYPE_INTERNAL_INT )
{
bro_int_t i = op->ExprVal()->InternalInt();
double d = double(i);
if ( i != bro_int_t(d) )
Warn("coercion loses precision");
return new ConstExpr(new Val(d, type->Tag()));
}
if ( op_int == TYPE_INTERNAL_UNSIGNED )
{
bro_uint_t u = op->ExprVal()->InternalUnsigned();
double d = double(u);
if ( u != (bro_uint_t) (d) )
Warn("coercion loses precision");
return new ConstExpr(new Val(d, type->Tag()));
}
}
Internal("bad coercion in CoerceExpr::DoSimplify");
}
return this;
}
Val* ArithCoerceExpr::FoldSingleVal(Val* v, InternalTypeTag t) const
{
switch ( t ) {
@ -4186,6 +3804,9 @@ RecordCoerceExpr::RecordCoerceExpr(Expr* op, RecordType* r)
map[t_i] = i;
}
if ( IsError() )
return;
for ( i = 0; i < map_size; ++i )
{
if ( map[i] == -1 )
@ -4550,22 +4171,6 @@ int ScheduleExpr::IsPure() const
return 0;
}
Expr* ScheduleExpr::Simplify(SimplifyType simp_type)
{
when = when->Simplify(simp_type);
Expr* generic_event = event->Simplify(simp_type);
if ( ! generic_event )
return 0;
if ( generic_event->Tag() != EXPR_CALL )
Internal("bad event type in ScheduleExpr::Simplify");
event = (EventExpr*) generic_event;
return this;
}
Val* ScheduleExpr::Eval(Frame* f) const
{
if ( terminating )
@ -4898,20 +4503,6 @@ int CallExpr::IsPure() const
return pure;
}
Expr* CallExpr::Simplify(SimplifyType /* simp_type */)
{
if ( IsError() )
return this;
func = simplify_expr(func, SIMPLIFY_GENERAL);
args = simplify_expr_list(args, SIMPLIFY_GENERAL);
if ( IsPure() )
return new ConstExpr(Eval(0));
else
return this;
}
Val* CallExpr::Eval(Frame* f) const
{
if ( IsError() )
@ -5064,14 +4655,6 @@ EventExpr::~EventExpr()
Unref(args);
}
Expr* EventExpr::Simplify(SimplifyType /* simp_type */)
{
if ( ! IsError() )
args = simplify_expr_list(args, SIMPLIFY_GENERAL);
return this;
}
Val* EventExpr::Eval(Frame* f) const
{
if ( IsError() )
@ -5178,17 +4761,6 @@ int ListExpr::AllConst() const
return 1;
}
Expr* ListExpr::Simplify(SimplifyType /* simp_type */)
{
loop_over_list(exprs, i)
exprs.replace(i, simplify_expr(exprs[i], SIMPLIFY_GENERAL));
// Note that we do *not* simplify a list with one element
// to just that element. The assumption that simplify_expr(ListExpr*)
// returns a ListExpr* is widespread.
return this;
}
Val* ListExpr::Eval(Frame* f) const
{
ListVal* v = new ListVal(TYPE_ANY);
@ -5820,25 +5392,6 @@ int check_and_promote_exprs_to_type(ListExpr*& elements, BroType* type)
return 1;
}
Expr* simplify_expr(Expr* e, SimplifyType simp_type)
{
if ( ! e )
return 0;
for ( Expr* s = e->Simplify(simp_type); s != e; s = e->Simplify(simp_type) )
{
Unref(e);
e = s;
}
return e;
}
ListExpr* simplify_expr_list(ListExpr* l, SimplifyType simp_type)
{
return (ListExpr*) simplify_expr(l, simp_type);
}
val_list* eval_list(Frame* f, const ListExpr* l)
{
const expr_list& e = l->Exprs();
@ -5864,129 +5417,6 @@ val_list* eval_list(Frame* f, const ListExpr* l)
return v;
}
int same_expr(const Expr* e1, const Expr* e2)
{
if ( e1 == e2 )
return 1;
if ( e1->Tag() != e2->Tag() || ! same_type(e1->Type(), e2->Type()) )
return 0;
if ( e1->IsError() || e2->IsError() )
return 0;
switch ( e1->Tag() ) {
case EXPR_NAME:
{
const NameExpr* n1 = (NameExpr*) e1;
const NameExpr* n2 = (NameExpr*) e2;
return n1->Id() == n2->Id();
}
case EXPR_CONST:
{
const ConstExpr* c1 = (ConstExpr*) e1;
const ConstExpr* c2 = (ConstExpr*) e2;
return same_val(c1->Value(), c2->Value());
}
case EXPR_INCR:
case EXPR_DECR:
case EXPR_NOT:
case EXPR_NEGATE:
case EXPR_POSITIVE:
case EXPR_REF:
case EXPR_RECORD_CONSTRUCTOR:
case EXPR_TABLE_CONSTRUCTOR:
case EXPR_SET_CONSTRUCTOR:
case EXPR_VECTOR_CONSTRUCTOR:
case EXPR_FIELD_ASSIGN:
case EXPR_ARITH_COERCE:
case EXPR_RECORD_COERCE:
case EXPR_TABLE_COERCE:
case EXPR_FLATTEN:
{
const UnaryExpr* u1 = (UnaryExpr*) e1;
const UnaryExpr* u2 = (UnaryExpr*) e2;
return same_expr(u1->Op(), u2->Op());
}
case EXPR_FIELD:
{
const FieldExpr* f1 = (FieldExpr*) e1;
const FieldExpr* f2 = (FieldExpr*) e2;
return same_expr(f1->Op(), f2->Op()) &&
f1->Field() == f2->Field();
}
case EXPR_SCHEDULE:
{
const ScheduleExpr* s1 = (ScheduleExpr*) e1;
const ScheduleExpr* s2 = (ScheduleExpr*) e2;
return same_expr(s1->When(), s2->When()) &&
same_expr(s1->Event(), s2->Event());
}
case EXPR_ADD:
case EXPR_ADD_TO:
case EXPR_SUB:
case EXPR_REMOVE_FROM:
case EXPR_TIMES:
case EXPR_DIVIDE:
case EXPR_MOD:
case EXPR_AND:
case EXPR_OR:
case EXPR_LT:
case EXPR_LE:
case EXPR_EQ:
case EXPR_NE:
case EXPR_GE:
case EXPR_GT:
case EXPR_ASSIGN:
case EXPR_MATCH:
case EXPR_INDEX:
case EXPR_IN:
{
const BinaryExpr* b1 = (BinaryExpr*) e1;
const BinaryExpr* b2 = (BinaryExpr*) e2;
return same_expr(b1->Op1(), b2->Op1()) &&
same_expr(b1->Op2(), b2->Op2());
}
case EXPR_LIST:
{
const ListExpr* l1 = (ListExpr*) e1;
const ListExpr* l2 = (ListExpr*) e2;
const expr_list& le1 = l1->Exprs();
const expr_list& le2 = l2->Exprs();
if ( le1.length() != le2.length() )
return 0;
loop_over_list(le1, i)
if ( ! same_expr(le1[i], le2[i]) )
return 0;
return 1;
}
case EXPR_CALL:
{
const CallExpr* c1 = (CallExpr*) e1;
const CallExpr* c2 = (CallExpr*) e2;
return same_expr(c1->Func(), c2->Func()) &&
c1->IsPure() && same_expr(c1->Args(), c2->Args());
}
default:
reporter->InternalError("bad tag in same_expr()");
}
return 0;
}
int expr_greater(const Expr* e1, const Expr* e2)
{
return int(e1->Tag()) > int(e2->Tag());

View file

@ -47,11 +47,6 @@ typedef enum {
#define NUM_EXPRS (int(EXPR_FLATTEN) + 1)
} BroExprTag;
typedef enum {
SIMPLIFY_GENERAL, // regular simplification
SIMPLIFY_LHS, // simplify as the LHS of an assignment
} SimplifyType;
extern const char* expr_name(BroExprTag t);
class Stmt;
@ -72,11 +67,6 @@ public:
Expr* Ref() { ::Ref(this); return this; }
// Returns a fully simplified version of the expression (this
// may be the same expression, or a newly created one). simp_type
// gives the context of the simplification.
virtual Expr* Simplify(SimplifyType simp_type) = 0;
// Evaluates the expression and returns a corresponding Val*,
// or nil if the expression's value isn't fixed.
virtual Val* Eval(Frame* f) const = 0;
@ -230,7 +220,6 @@ public:
ID* Id() const { return id; }
Expr* Simplify(SimplifyType simp_type);
Val* Eval(Frame* f) const;
void Assign(Frame* f, Val* v, Opcode op = OP_ASSIGN);
Expr* MakeLvalue();
@ -257,7 +246,6 @@ public:
Val* Value() const { return val; }
Expr* Simplify(SimplifyType simp_type);
Val* Eval(Frame* f) const;
TraversalCode Traverse(TraversalCallback* cb) const;
@ -276,9 +264,6 @@ class UnaryExpr : public Expr {
public:
Expr* Op() const { return op; }
// Simplifies the operand and calls DoSimplify().
virtual Expr* Simplify(SimplifyType simp_type);
// UnaryExpr::Eval correctly handles vector types. Any child
// class that overrides Eval() should be modified to handle
// vectors correctly as necessary.
@ -297,10 +282,6 @@ protected:
void ExprDescribe(ODesc* d) const;
// Can be overridden by subclasses that want to take advantage
// of UnaryExpr's Simplify() method.
virtual Expr* DoSimplify();
// Returns the expression folded using the given constant.
virtual Val* Fold(Val* v) const;
@ -314,9 +295,6 @@ public:
Expr* Op1() const { return op1; }
Expr* Op2() const { return op2; }
// Simplifies both operands, folds them if constant,
// otherwise calls DoSimplify().
virtual Expr* Simplify(SimplifyType simp_type);
int IsPure() const;
// BinaryExpr::Eval correctly handles vector types. Any child
@ -340,10 +318,6 @@ protected:
}
virtual ~BinaryExpr();
// Can be overridden by subclasses that want to take advantage
// of BinaryExpr's Simplify() method.
virtual Expr* DoSimplify();
// Returns the expression folded using the given constants.
virtual Val* Fold(Val* v1, Val* v2) const;
@ -356,9 +330,6 @@ protected:
int BothConst() const { return op1->IsConst() && op2->IsConst(); }
// Simplify both operands and canonicize.
void SimplifyOps();
// Exchange op1 and op2.
void SwapOps();
@ -414,7 +385,6 @@ protected:
friend class Expr;
NotExpr() { }
Expr* DoSimplify();
Val* Fold(Val* v) const;
DECLARE_SERIAL(NotExpr);
@ -428,7 +398,6 @@ protected:
friend class Expr;
PosExpr() { }
Expr* DoSimplify();
Val* Fold(Val* v) const;
DECLARE_SERIAL(PosExpr);
@ -442,7 +411,6 @@ protected:
friend class Expr;
NegExpr() { }
Expr* DoSimplify();
Val* Fold(Val* v) const;
DECLARE_SERIAL(NegExpr);
@ -470,8 +438,6 @@ protected:
friend class Expr;
AddExpr() { }
Expr* DoSimplify();
DECLARE_SERIAL(AddExpr);
};
@ -508,8 +474,6 @@ protected:
friend class Expr;
SubExpr() { }
Expr* DoSimplify();
DECLARE_SERIAL(SubExpr);
};
@ -523,8 +487,6 @@ protected:
friend class Expr;
TimesExpr() { }
Expr* DoSimplify();
DECLARE_SERIAL(TimesExpr);
};
@ -538,7 +500,6 @@ protected:
DivideExpr() { }
Val* AddrFold(Val* v1, Val* v2) const;
Expr* DoSimplify();
DECLARE_SERIAL(DivideExpr);
@ -552,8 +513,6 @@ protected:
friend class Expr;
ModExpr() { }
Expr* DoSimplify();
DECLARE_SERIAL(ModExpr);
};
@ -568,8 +527,6 @@ protected:
friend class Expr;
BoolExpr() { }
Expr* DoSimplify();
DECLARE_SERIAL(BoolExpr);
};
@ -582,8 +539,6 @@ protected:
friend class Expr;
EqExpr() { }
Expr* DoSimplify();
Val* Fold(Val* v1, Val* v2) const;
DECLARE_SERIAL(EqExpr);
@ -598,8 +553,6 @@ protected:
friend class Expr;
RelExpr() { }
Expr* DoSimplify();
DECLARE_SERIAL(RelExpr);
};
@ -612,7 +565,6 @@ public:
const Expr* Op2() const { return op2; }
const Expr* Op3() const { return op3; }
Expr* Simplify(SimplifyType simp_type);
Val* Eval(Frame* f) const;
int IsPure() const;
@ -652,7 +604,6 @@ public:
AssignExpr(Expr* op1, Expr* op2, int is_init, Val* val = 0, attr_list* attrs = 0);
virtual ~AssignExpr() { Unref(val); }
Expr* Simplify(SimplifyType simp_type);
Val* Eval(Frame* f) const;
void EvalIntoAggregate(const BroType* t, Val* aggr, Frame* f) const;
BroType* InitType() const;
@ -683,7 +634,6 @@ public:
void Add(Frame* f);
void Delete(Frame* f);
Expr* Simplify(SimplifyType simp_type);
void Assign(Frame* f, Val* v, Opcode op = OP_ASSIGN);
Expr* MakeLvalue();
@ -714,7 +664,6 @@ public:
int CanDel() const;
Expr* Simplify(SimplifyType simp_type);
void Assign(Frame* f, Val* v, Opcode op = OP_ASSIGN);
void Delete(Frame* f);
@ -866,8 +815,6 @@ protected:
friend class Expr;
ArithCoerceExpr() { }
Expr* DoSimplify();
Val* FoldSingleVal(Val* v, InternalTypeTag t) const;
Val* Fold(Val* v) const;
@ -962,8 +909,6 @@ public:
int IsPure() const;
Expr* Simplify(SimplifyType simp_type);
Val* Eval(Frame* f) const;
Expr* When() const { return when; }
@ -1007,7 +952,6 @@ public:
int IsPure() const;
Expr* Simplify(SimplifyType simp_type);
Val* Eval(Frame* f) const;
TraversalCode Traverse(TraversalCallback* cb) const;
@ -1033,7 +977,6 @@ public:
ListExpr* Args() const { return args; }
EventHandlerPtr Handler() const { return handler; }
Expr* Simplify(SimplifyType simp_type);
Val* Eval(Frame* f) const;
TraversalCode Traverse(TraversalCallback* cb) const;
@ -1068,7 +1011,6 @@ public:
// True if the entire list represents constant values.
int AllConst() const;
Expr* Simplify(SimplifyType simp_type);
Val* Eval(Frame* f) const;
BroType* InitType() const;
@ -1127,21 +1069,10 @@ extern int check_and_promote_exprs(ListExpr*& elements, TypeList* types);
extern int check_and_promote_args(ListExpr*& args, RecordType* types);
extern int check_and_promote_exprs_to_type(ListExpr*& elements, BroType* type);
// Returns a fully simplified form of the expression. Note that passed
// expression and its subexpressions may be modified, Unref()'d, etc.
Expr* simplify_expr(Expr* e, SimplifyType simp_type);
// Returns a simplified ListExpr - guaranteed to still be a ListExpr,
// even if it only contains one expr.
ListExpr* simplify_expr_list(ListExpr* l, SimplifyType simp_type);
// Returns a ListExpr simplified down to a list a values, or a nil
// pointer if they couldn't all be reduced.
val_list* eval_list(Frame* f, const ListExpr* l);
// Returns true if two expressions are identical.
extern int same_expr(const Expr* e1, const Expr* e2);
// Returns true if e1 is "greater" than e2 - here "greater" is just
// a heuristic, used with commutative operators to put them into
// a canonical form.

View file

@ -10,6 +10,7 @@ RecordType* endpoint;
RecordType* endpoint_stats;
RecordType* connection_type;
RecordType* fa_file_type;
RecordType* fa_metadata_type;
RecordType* icmp_conn;
RecordType* icmp_context;
RecordType* SYN_packet;
@ -318,6 +319,7 @@ void init_net_var()
endpoint_stats = internal_type("endpoint_stats")->AsRecordType();
connection_type = internal_type("connection")->AsRecordType();
fa_file_type = internal_type("fa_file")->AsRecordType();
fa_metadata_type = internal_type("fa_metadata")->AsRecordType();
icmp_conn = internal_type("icmp_conn")->AsRecordType();
icmp_context = internal_type("icmp_context")->AsRecordType();
signature_state = internal_type("signature_state")->AsRecordType();

View file

@ -13,6 +13,7 @@ extern RecordType* endpoint;
extern RecordType* endpoint_stats;
extern RecordType* connection_type;
extern RecordType* fa_file_type;
extern RecordType* fa_metadata_type;
extern RecordType* icmp_conn;
extern RecordType* icmp_context;
extern RecordType* signature_state;

View file

@ -79,11 +79,6 @@ bool Stmt::SetLocationInfo(const Location* start, const Location* end)
return true;
}
Stmt* Stmt::Simplify()
{
return this;
}
int Stmt::IsPure() const
{
return 0;
@ -201,18 +196,6 @@ Val* ExprListStmt::Exec(Frame* f, stmt_flow_type& flow) const
return 0;
}
Stmt* ExprListStmt::Simplify()
{
l = simplify_expr_list(l, SIMPLIFY_GENERAL);
DoSimplify();
return this;
}
Stmt* ExprListStmt::DoSimplify()
{
return this;
}
void ExprListStmt::Describe(ODesc* d) const
{
Stmt::Describe(d);
@ -383,17 +366,6 @@ Val* ExprStmt::DoExec(Frame* /* f */, Val* /* v */, stmt_flow_type& /* flow */)
return 0;
}
Stmt* ExprStmt::Simplify()
{
e = simplify_expr(e, SIMPLIFY_GENERAL);
return DoSimplify();
}
Stmt* ExprStmt::DoSimplify()
{
return this;
}
int ExprStmt::IsPure() const
{
return ! e || e->IsPure();
@ -490,33 +462,6 @@ Val* IfStmt::DoExec(Frame* f, Val* v, stmt_flow_type& flow) const
return result;
}
Stmt* IfStmt::DoSimplify()
{
s1 = simplify_stmt(s1);
s2 = simplify_stmt(s2);
if ( e->IsConst() )
{
if ( ! optimize )
Warn("constant in conditional");
return e->IsZero() ? s2->Ref() : s1->Ref();
}
if ( e->Tag() == EXPR_NOT )
{
Stmt* t = s1;
s1 = s2;
s2 = t;
e = new NotExpr(e);
return Simplify();
}
return this;
}
int IfStmt::IsPure() const
{
return e->IsPure() && s1->IsPure() && s2->IsPure();
@ -602,7 +547,7 @@ static BroStmtTag get_last_stmt_tag(const Stmt* stmt)
}
Case::Case(ListExpr* c, Stmt* arg_s)
: cases(simplify_expr_list(c, SIMPLIFY_GENERAL)), s(arg_s)
: cases(c), s(arg_s)
{
BroStmtTag t = get_last_stmt_tag(Body());
@ -729,8 +674,8 @@ SwitchStmt::SwitchStmt(Expr* index, case_list* arg_cases) :
loop_over_list(*cases, i)
{
const Case* c = (*cases)[i];
const ListExpr* le = c->Cases();
Case* c = (*cases)[i];
ListExpr* le = c->Cases();
if ( le )
{
@ -740,10 +685,53 @@ SwitchStmt::SwitchStmt(Expr* index, case_list* arg_cases) :
continue;
}
const expr_list& exprs = le->Exprs();
expr_list& exprs = le->Exprs();
loop_over_list(exprs, j)
{
if ( ! exprs[j]->IsConst() )
{
Expr* expr = exprs[j];
switch ( expr->Tag() ) {
// Simplify trivial unary plus/minus expressions on consts.
case EXPR_NEGATE:
{
NegExpr* ne = (NegExpr*)(expr);
if ( ne->Op()->IsConst() )
Unref(exprs.replace(j, new ConstExpr(ne->Eval(0))));
}
break;
case EXPR_POSITIVE:
{
PosExpr* pe = (PosExpr*)(expr);
if ( pe->Op()->IsConst() )
Unref(exprs.replace(j, new ConstExpr(pe->Eval(0))));
}
break;
case EXPR_NAME:
{
NameExpr* ne = (NameExpr*)(expr);
if ( ne->Id()->IsConst() )
{
Val* v = ne->Eval(0);
if ( v )
Unref(exprs.replace(j, new ConstExpr(v)));
}
}
break;
default:
break;
}
}
if ( ! exprs[j]->IsConst() )
exprs[j]->Error("case label expression isn't constant");
else
@ -845,36 +833,6 @@ Val* SwitchStmt::DoExec(Frame* f, Val* v, stmt_flow_type& flow) const
return rval;
}
Stmt* SwitchStmt::DoSimplify()
{
loop_over_list(*cases, i)
{
Case* c = (*cases)[i];
ListExpr* new_cases = simplify_expr_list(c->Cases(), SIMPLIFY_GENERAL);
Stmt* new_body = simplify_stmt(c->Body());
if ( new_cases != c->Cases() || new_body != c->Body() )
{
cases->replace(i, new Case(new_cases, new_body));
Unref(c);
}
}
if ( e->IsConst() )
{
// Could possibly remove all case labels before the one
// that will match, but may be tricky to tell if any
// subsequent ones can also be removed since it depends
// on the evaluation of the body executing a break/return
// statement. Then still need a way to bypass the lookup
// DoExec for it to be beneficial.
if ( ! optimize )
Warn("constant in switch");
}
return this;
}
int SwitchStmt::IsPure() const
{
if ( ! e->IsPure() )
@ -1212,17 +1170,6 @@ Val* WhileStmt::Exec(Frame* f, stmt_flow_type& flow) const
return rval;
}
Stmt* WhileStmt::Simplify()
{
loop_condition = simplify_expr(loop_condition, SIMPLIFY_GENERAL);
if ( loop_condition->IsConst() && loop_condition->IsZero() )
return new NullStmt();
body = simplify_stmt(body);
return this;
}
IMPLEMENT_SERIAL(WhileStmt, SER_WHILE_STMT);
bool WhileStmt::DoSerialize(SerialInfo* info) const
@ -1416,21 +1363,6 @@ Val* ForStmt::DoExec(Frame* f, Val* v, stmt_flow_type& flow) const
return ret;
}
Stmt* ForStmt::DoSimplify()
{
body = simplify_stmt(body);
if ( e->IsConst() )
{
const PDict(TableEntryVal)* vt = e->ExprVal()->AsTable();
if ( vt->Length() == 0 )
return new NullStmt();
}
return this;
}
int ForStmt::IsPure() const
{
return e->IsPure() && body->IsPure();
@ -1774,20 +1706,6 @@ Val* StmtList::Exec(Frame* f, stmt_flow_type& flow) const
return 0;
}
Stmt* StmtList::Simplify()
{
if ( stmts.length() == 0 )
return new NullStmt();
if ( stmts.length() == 1 )
return stmts[0]->Ref();
loop_over_list(stmts, i)
stmts.replace(i, simplify_stmt(stmts[i]));
return this;
}
int StmtList::IsPure() const
{
loop_over_list(stmts, i)
@ -1909,17 +1827,6 @@ Val* EventBodyList::Exec(Frame* f, stmt_flow_type& flow) const
return 0;
}
Stmt* EventBodyList::Simplify()
{
if ( stmts.length() <= 1 )
// Don't simplify these, we don't want to lose our
// "execute even across returns" property.
return this;
else
return StmtList::Simplify();
}
void EventBodyList::Describe(ODesc* d) const
{
if ( d->IsReadable() && stmts.length() > 0 )
@ -2168,19 +2075,6 @@ Val* WhenStmt::Exec(Frame* f, stmt_flow_type& flow) const
return 0;
}
Stmt* WhenStmt::Simplify()
{
cond = simplify_expr(cond, SIMPLIFY_GENERAL);
s1 = simplify_stmt(s1);
if ( s2 )
s2 = simplify_stmt(s2);
if ( cond->IsPure() )
Warn("non-varying expression in when clause");
return this;
}
int WhenStmt::IsPure() const
{
return cond->IsPure() && s1->IsPure() && (! s2 || s2->IsPure());
@ -2276,172 +2170,3 @@ bool WhenStmt::DoUnserialize(UnserialInfo* info)
return true;
}
Stmt* simplify_stmt(Stmt* s)
{
for ( Stmt* ss = s->Simplify(); ss != s; ss = s->Simplify() )
{
Unref(s);
s = ss;
}
return s;
}
int same_stmt(const Stmt* s1, const Stmt* s2)
{
if ( s1 == s2 )
return 1;
if ( s1->Tag() != s2->Tag() )
return 0;
switch ( s1->Tag() ) {
case STMT_PRINT:
{
const ListExpr* l1 = ((const ExprListStmt*) s1)->ExprList();
const ListExpr* l2 = ((const ExprListStmt*) s2)->ExprList();
return same_expr(l1, l2);
}
case STMT_ADD:
case STMT_DELETE:
case STMT_RETURN:
case STMT_EXPR:
case STMT_EVENT:
{
const ExprStmt* e1 = (const ExprStmt*) s1;
const ExprStmt* e2 = (const ExprStmt*) s2;
return same_expr(e1->StmtExpr(), e2->StmtExpr());
}
case STMT_FOR:
{
const ForStmt* f1 = (const ForStmt*) s1;
const ForStmt* f2 = (const ForStmt*) s2;
return f1->LoopVar() == f2->LoopVar() &&
same_expr(f1->LoopExpr(), f2->LoopExpr()) &&
same_stmt(f1->LoopBody(), f2->LoopBody());
}
case STMT_IF:
{
const IfStmt* i1 = (const IfStmt*) s1;
const IfStmt* i2 = (const IfStmt*) s2;
if ( ! same_expr(i1->StmtExpr(), i2->StmtExpr()) )
return 0;
if ( i1->TrueBranch() || i2->TrueBranch() )
{
if ( ! i1->TrueBranch() || ! i2->TrueBranch() )
return 0;
if ( ! same_stmt(i1->TrueBranch(), i2->TrueBranch()) )
return 0;
}
if ( i1->FalseBranch() || i2->FalseBranch() )
{
if ( ! i1->FalseBranch() || ! i2->FalseBranch() )
return 0;
if ( ! same_stmt(i1->FalseBranch(), i2->FalseBranch()) )
return 0;
}
return 1;
}
case STMT_SWITCH:
{
const SwitchStmt* sw1 = (const SwitchStmt*) s1;
const SwitchStmt* sw2 = (const SwitchStmt*) s2;
if ( ! same_expr(sw1->StmtExpr(), sw2->StmtExpr()) )
return 0;
const case_list* c1 = sw1->Cases();
const case_list* c2 = sw1->Cases();
if ( c1->length() != c2->length() )
return 0;
loop_over_list(*c1, i)
{
if ( ! same_expr((*c1)[i]->Cases(), (*c2)[i]->Cases()) )
return 0;
if ( ! same_stmt((*c1)[i]->Body(), (*c2)[i]->Body()) )
return 0;
}
return 1;
}
case STMT_LIST:
case STMT_EVENT_BODY_LIST:
{
const stmt_list& l1 = ((const StmtList*) s1)->Stmts();
const stmt_list& l2 = ((const StmtList*) s2)->Stmts();
if ( l1.length() != l2.length() )
return 0;
loop_over_list(l1, i)
if ( ! same_stmt(l1[i], l2[i]) )
return 0;
return 1;
}
case STMT_INIT:
{
const id_list* i1 = ((const InitStmt*) s1)->Inits();
const id_list* i2 = ((const InitStmt*) s2)->Inits();
if ( i1->length() != i2->length() )
return 0;
loop_over_list(*i1, i)
if ( (*i1)[i] != (*i2)[i] )
return 0;
return 1;
}
case STMT_WHEN:
{
const WhenStmt* w1 = (const WhenStmt*) s1;
const WhenStmt* w2 = (const WhenStmt*) s2;
if ( ! same_expr(w1->Cond(), w2->Cond()) )
return 0;
if ( ! same_stmt(w1->Body(), w2->Body()) )
return 0;
if ( w1->TimeoutBody() || w2->TimeoutBody() )
{
if ( ! w1->TimeoutBody() || ! w2->TimeoutBody() )
return 0;
if ( ! same_expr(w1->TimeoutExpr(), w2->TimeoutExpr()) )
return 0;
if ( ! same_stmt(w1->TimeoutBody(), w2->TimeoutBody()) )
return 0;
}
return 1;
}
case STMT_NEXT:
case STMT_BREAK:
case STMT_NULL:
return 1;
default:
reporter->Error("bad tag in same_stmt()");
}
return 0;
}

View file

@ -33,10 +33,6 @@ public:
{ return Stmt::SetLocationInfo(loc, loc); }
bool SetLocationInfo(const Location* start, const Location* end);
// Returns a fully simplified version of the statement (this
// may be the same statement, or a newly created one).
virtual Stmt* Simplify();
// True if the statement has no side effects, false otherwise.
virtual int IsPure() const;
@ -112,9 +108,6 @@ protected:
Val* Exec(Frame* f, stmt_flow_type& flow) const;
virtual Val* DoExec(val_list* vals, stmt_flow_type& flow) const = 0;
Stmt* Simplify();
virtual Stmt* DoSimplify();
void Describe(ODesc* d) const;
void PrintVals(ODesc* d, val_list* vals, int offset) const;
@ -156,12 +149,8 @@ protected:
virtual Val* DoExec(Frame* f, Val* v, stmt_flow_type& flow) const;
Stmt* Simplify();
int IsPure() const;
// Called by Simplify(), after the expression's been simplified.
virtual Stmt* DoSimplify();
DECLARE_SERIAL(ExprStmt);
Expr* e;
@ -184,7 +173,6 @@ protected:
IfStmt() { s1 = s2 = 0; }
Val* DoExec(Frame* f, Val* v, stmt_flow_type& flow) const;
Stmt* DoSimplify();
int IsPure() const;
DECLARE_SERIAL(IfStmt);
@ -237,7 +225,6 @@ protected:
SwitchStmt() { cases = 0; default_case_idx = -1; comp_hash = 0; }
Val* DoExec(Frame* f, Val* v, stmt_flow_type& flow) const;
Stmt* DoSimplify();
int IsPure() const;
DECLARE_SERIAL(SwitchStmt);
@ -329,7 +316,6 @@ protected:
{ loop_condition = 0; body = 0; }
Val* Exec(Frame* f, stmt_flow_type& flow) const;
Stmt* Simplify();
DECLARE_SERIAL(WhileStmt);
@ -359,7 +345,6 @@ protected:
ForStmt() { loop_vars = 0; body = 0; }
Val* DoExec(Frame* f, Val* v, stmt_flow_type& flow) const;
Stmt* DoSimplify();
DECLARE_SERIAL(ForStmt);
@ -442,7 +427,6 @@ public:
TraversalCode Traverse(TraversalCallback* cb) const;
protected:
Stmt* Simplify();
int IsPure() const;
DECLARE_SERIAL(StmtList);
@ -464,7 +448,6 @@ public:
// bool IsTopmost() { return topmost; }
protected:
Stmt* Simplify();
DECLARE_SERIAL(EventBodyList);
@ -522,7 +505,6 @@ public:
Val* Exec(Frame* f, stmt_flow_type& flow) const;
int IsPure() const;
Stmt* Simplify();
const Expr* Cond() const { return cond; }
const Stmt* Body() const { return s1; }
@ -545,7 +527,4 @@ protected:
bool is_return;
};
extern Stmt* simplify_stmt(Stmt* s);
extern int same_stmt(const Stmt* s1, const Stmt* s2);
#endif

View file

@ -1977,18 +1977,33 @@ int same_attrs(const Attributes* a1, const Attributes* a2)
return (*a1 == *a2);
}
int record_promotion_compatible(const RecordType* /* super_rec */,
const RecordType* /* sub_rec */)
int record_promotion_compatible(const RecordType* super_rec,
const RecordType* sub_rec)
{
#if 0
int n = sub_rec->NumFields();
for ( int i = 0; i < n; ++i )
for ( int i = 0; i < sub_rec->NumFields(); ++i )
{
if ( ! super_rec->HasField(sub_rec->FieldName(i)) )
int o = super_rec->FieldOffset(sub_rec->FieldName(i));
if ( o < 0 )
// Orphaned field.
continue;
BroType* sub_field_type = sub_rec->FieldType(i);
BroType* super_field_type = super_rec->FieldType(o);
if ( same_type(sub_field_type, super_field_type) )
continue;
if ( sub_field_type->Tag() != TYPE_RECORD )
return 0;
if ( super_field_type->Tag() != TYPE_RECORD )
return 0;
if ( ! record_promotion_compatible(super_field_type->AsRecordType(),
sub_field_type->AsRecordType()) )
return 0;
}
#endif
return 1;
}

View file

@ -2985,8 +2985,10 @@ bool VectorVal::Assign(unsigned int index, Val* element, Opcode op)
}
}
Val* val_at_index = 0;
if ( index < val.vector_val->size() )
Unref((*val.vector_val)[index]);
val_at_index = (*val.vector_val)[index];
else
val.vector_val->resize(index + 1);
@ -2999,10 +3001,12 @@ bool VectorVal::Assign(unsigned int index, Val* element, Opcode op)
StateAccess::Log(new StateAccess(op == OP_INCR ?
OP_INCR_IDX : OP_ASSIGN_IDX,
this, ival, element, (*val.vector_val)[index]));
this, ival, element, val_at_index));
Unref(ival);
}
Unref(val_at_index);
// Note: we do *not* Ref() the element, if any, at this point.
// AssignExpr::Eval() already does this; other callers must remember
// to do it similarly.

View file

@ -64,9 +64,6 @@ static void make_var(ID* id, BroType* t, init_class c, Expr* init,
}
}
if ( init && optimize )
init = init->Simplify(SIMPLIFY_GENERAL);
if ( t && t->IsSet() )
{ // Check for set with explicit elements.
SetType* st = t->AsTableType()->AsSetType();

View file

@ -18,19 +18,20 @@ add_subdirectory(icmp)
add_subdirectory(ident)
add_subdirectory(interconn)
add_subdirectory(irc)
add_subdirectory(krb)
add_subdirectory(login)
add_subdirectory(mime)
add_subdirectory(modbus)
add_subdirectory(mysql)
add_subdirectory(ncp)
add_subdirectory(netbios)
add_subdirectory(netflow)
add_subdirectory(ntp)
add_subdirectory(pia)
add_subdirectory(pop3)
add_subdirectory(radius)
add_subdirectory(rdp)
add_subdirectory(rpc)
add_subdirectory(sip)
add_subdirectory(snmp)
add_subdirectory(smb)
add_subdirectory(smtp)

View file

@ -0,0 +1,194 @@
%extern{
#include <cstdlib>
%}
%header{
Val* asn1_integer_to_val(const ASN1Encoding* i, TypeTag t);
Val* asn1_integer_to_val(const ASN1Integer* i, TypeTag t);
StringVal* asn1_oid_to_val(const ASN1Encoding* oid);
StringVal* asn1_oid_to_val(const ASN1ObjectIdentifier* oid);
StringVal* asn1_octet_string_to_val(const ASN1Encoding* s);
StringVal* asn1_octet_string_to_val(const ASN1OctetString* s);
%}
############################## ASN.1 Encodings
enum ASN1TypeTag {
ASN1_INTEGER_TAG = 0x02,
ASN1_OCTET_STRING_TAG = 0x04,
ASN1_NULL_TAG = 0x05,
ASN1_OBJECT_IDENTIFIER_TAG = 0x06,
ASN1_SEQUENCE_TAG = 0x30,
ASN1_APP_TAG_OFFSET = 0x60,
ASN1_INDEX_TAG_OFFSET = 0xa0,
};
type ASN1Encoding = record {
meta: ASN1EncodingMeta;
content: bytestring &length = meta.length;
};
type ASN1EncodingMeta = record {
tag: uint8;
len: uint8;
more_len: bytestring &length = long_len ? len & 0x7f : 0;
} &let {
long_len : bool = (len & 0x80) > 0;
length: uint64 = long_len ? binary_to_int64(more_len) : len;
index : uint8 = tag - ASN1_INDEX_TAG_OFFSET;
};
type ASN1OptionalEncodingMeta(is_present: bool, previous_metadata: ASN1EncodingMeta) = case is_present of {
true -> data: ASN1EncodingMeta;
false -> none: empty;
} &let {
length: uint64 = is_present ? data.length : previous_metadata.length;
};
type ASN1SequenceMeta = record {
encoding: ASN1EncodingMeta;
};
type ASN1Integer = record {
encoding: ASN1Encoding;
};
type ASN1OctetString = record {
encoding: ASN1Encoding;
};
type ASN1ObjectIdentifier = record {
encoding: ASN1Encoding;
};
type ASN1Boolean = record {
encoding: ASN1Encoding;
};
type ASN1Enumerated = record {
encoding: ASN1Encoding;
};
type SequenceElement(grab_content: bool) = record {
index_meta: ASN1EncodingMeta;
have_content: case grab_content of {
true -> data: ASN1Encoding;
false -> meta: ASN1EncodingMeta;
};
} &let {
index: uint8 = index_meta.index;
length: uint64 = index_meta.length;
};
type Array = record {
array_meta: ASN1EncodingMeta;
data: ASN1Encoding[];
};
############################## ASN.1 Conversion Functions
function binary_to_int64(bs: bytestring): int64
%{
int64 rval = 0;
for ( int i = 0; i < bs.length(); ++i )
{
uint64 byte = bs[i];
rval |= byte << (8 * (bs.length() - (i + 1)));
}
return rval;
%}
%code{
Val* asn1_integer_to_val(const ASN1Integer* i, TypeTag t)
{
return asn1_integer_to_val(i->encoding(), t);
}
Val* asn1_integer_to_val(const ASN1Encoding* i, TypeTag t)
{
return new Val(binary_to_int64(i->content()), t);
}
StringVal* asn1_oid_to_val(const ASN1ObjectIdentifier* oid)
{
return asn1_oid_to_val(oid->encoding());
}
StringVal* asn1_oid_to_val(const ASN1Encoding* oid)
{
vector<uint64> oid_components;
vector<vector<uint8> > subidentifiers;
vector<uint64> subidentifier_values;
vector<uint8> subidentifier;
bytestring const& bs = oid->content();
for ( int i = 0; i < bs.length(); ++i )
{
if ( bs[i] & 0x80 )
subidentifier.push_back(bs[i] & 0x7f);
else
{
subidentifier.push_back(bs[i]);
subidentifiers.push_back(subidentifier);
subidentifier.clear();
}
}
if ( ! subidentifier.empty() || subidentifiers.size() < 1 )
// Underflow.
return new StringVal("");
for ( size_t i = 0; i < subidentifiers.size(); ++i )
{
subidentifier = subidentifiers[i];
uint64 value = 0;
for ( size_t j = 0; j < subidentifier.size(); ++j )
{
uint64 byte = subidentifier[j];
value |= byte << (7 * (subidentifier.size() - (j + 1)));
}
subidentifier_values.push_back(value);
}
string rval;
for ( size_t i = 0; i < subidentifier_values.size(); ++i )
{
char tmp[32];
if ( i > 0 )
{
rval += ".";
snprintf(tmp, sizeof(tmp), "%" PRIu64, subidentifier_values[i]);
rval += tmp;
}
else
{
std::div_t result = std::div(subidentifier_values[i], 40);
snprintf(tmp, sizeof(tmp), "%d", result.quot);
rval += tmp;
rval += ".";
snprintf(tmp, sizeof(tmp), "%d", result.rem);
rval += tmp;
}
}
return new StringVal(rval);
}
StringVal* asn1_octet_string_to_val(const ASN1OctetString* s)
{
return asn1_octet_string_to_val(s->encoding());
}
StringVal* asn1_octet_string_to_val(const ASN1Encoding* s)
{
bytestring const& bs = s->content();
return new StringVal(bs.length(), reinterpret_cast<const char*>(bs.data()));
}
%}

View file

@ -6,7 +6,7 @@ include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DI
bro_plugin_begin(Bro DCE_RPC)
bro_plugin_cc(DCE_RPC.cc Plugin.cc)
bro_plugin_bif(events.bif)
bro_plugin_pac(dce_rpc.pac dce_rpc-protocol.pac dce_rpc-analyzer.pac)
bro_plugin_pac(dce_rpc.pac dce_rpc-protocol.pac dce_rpc-analyzer.pac epmapper.pac)
bro_plugin_pac(dce_rpc_simple.pac dce_rpc-protocol.pac epmapper.pac)
bro_plugin_end()

View file

@ -239,7 +239,9 @@ int HTTP_Entity::Undelivered(int64_t len)
len, expect_data_length);
}
if ( end_of_data && in_header )
// Don't propogate an entity (file) gap if we're still in the headers,
// or the body length was declared to be zero.
if ( (end_of_data && in_header) || body_length == 0 )
return 0;
if ( is_partial_content )

View file

@ -0,0 +1,26 @@
include(BroPlugin)
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR})
bro_plugin_begin(Bro KRB)
bro_plugin_cc(Plugin.cc)
bro_plugin_cc(KRB.cc)
bro_plugin_cc(KRB_TCP.cc)
bro_plugin_bif(types.bif)
bro_plugin_bif(events.bif)
bro_plugin_pac(krb.pac krb-protocol.pac krb-analyzer.pac
krb-asn1.pac
krb-defs.pac
krb-types.pac
krb-padata.pac
../asn1/asn1.pac
)
bro_plugin_pac(krb_TCP.pac krb-protocol.pac krb-analyzer.pac
krb-asn1.pac
krb-defs.pac
krb-types.pac
krb-padata.pac
../asn1/asn1.pac
)
bro_plugin_end()

View file

@ -0,0 +1,39 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include "KRB.h"
#include "types.bif.h"
#include "events.bif.h"
using namespace analyzer::krb;
KRB_Analyzer::KRB_Analyzer(Connection* conn)
: Analyzer("KRB", conn)
{
interp = new binpac::KRB::KRB_Conn(this);
}
KRB_Analyzer::~KRB_Analyzer()
{
delete interp;
}
void KRB_Analyzer::Done()
{
Analyzer::Done();
}
void KRB_Analyzer::DeliverPacket(int len, const u_char* data, bool orig,
uint64 seq, const IP_Hdr* ip, int caplen)
{
Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen);
try
{
interp->NewData(orig, data, data + len);
}
catch ( const binpac::Exception& e )
{
ProtocolViolation(e.c_msg());
}
}

View file

@ -0,0 +1,30 @@
// See the file "COPYING" in the main distribution directory for copyright.
#ifndef ANALYZER_PROTOCOL_KRB_KRB_H
#define ANALYZER_PROTOCOL_KRB_KRB_H
#include "krb_pac.h"
namespace analyzer { namespace krb {
class KRB_Analyzer : public analyzer::Analyzer {
public:
KRB_Analyzer(Connection* conn);
virtual ~KRB_Analyzer();
virtual void Done();
virtual void DeliverPacket(int len, const u_char* data, bool orig,
uint64 seq, const IP_Hdr* ip, int caplen);
static analyzer::Analyzer* Instantiate(Connection* conn)
{ return new KRB_Analyzer(conn); }
protected:
binpac::KRB::KRB_Conn* interp;
};
} } // namespace analyzer::*
#endif

View file

@ -0,0 +1,65 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include "KRB_TCP.h"
#include "analyzer/protocol/tcp/TCP_Reassembler.h"
#include "types.bif.h"
#include "events.bif.h"
using namespace analyzer::krb_tcp;
KRB_Analyzer::KRB_Analyzer(Connection* conn)
: tcp::TCP_ApplicationAnalyzer("KRB_TCP", conn)
{
interp = new binpac::KRB_TCP::KRB_Conn(this);
had_gap = false;
}
KRB_Analyzer::~KRB_Analyzer()
{
delete interp;
}
void KRB_Analyzer::Done()
{
tcp::TCP_ApplicationAnalyzer::Done();
interp->FlowEOF(true);
interp->FlowEOF(false);
}
void KRB_Analyzer::EndpointEOF(bool is_orig)
{
tcp::TCP_ApplicationAnalyzer::EndpointEOF(is_orig);
interp->FlowEOF(is_orig);
}
void KRB_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
{
tcp::TCP_ApplicationAnalyzer::DeliverStream(len, data, orig);
assert(TCP());
if ( TCP()->IsPartial() )
return;
if ( had_gap )
// If only one side had a content gap, we could still try to
// deliver data to the other side if the script layer can
// handle this.
return;
try
{
interp->NewData(orig, data, data + len);
}
catch ( const binpac::Exception& e )
{
ProtocolViolation(e.c_msg());
}
}
void KRB_Analyzer::Undelivered(uint64 seq, int len, bool orig)
{
tcp::TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
had_gap = true;
interp->NewGap(orig, len);
}

View file

@ -0,0 +1,35 @@
// See the file "COPYING" in the main distribution directory for copyright.
#ifndef ANALYZER_PROTOCOL_KRB_KRB_TCP_H
#define ANALYZER_PROTOCOL_KRB_KRB_TCP_H
#include "analyzer/protocol/tcp/TCP.h"
#include "krb_TCP_pac.h"
namespace analyzer { namespace krb_tcp {
class KRB_Analyzer : public tcp::TCP_ApplicationAnalyzer {
public:
KRB_Analyzer(Connection* conn);
virtual ~KRB_Analyzer();
virtual void Done();
virtual void DeliverStream(int len, const u_char* data, bool orig);
virtual void Undelivered(uint64 seq, int len, bool orig);
// Overriden from tcp::TCP_ApplicationAnalyzer.
virtual void EndpointEOF(bool is_orig);
static analyzer::Analyzer* Instantiate(Connection* conn)
{ return new KRB_Analyzer(conn); }
protected:
binpac::KRB_TCP::KRB_Conn* interp;
bool had_gap;
};
} } // namespace analyzer::*
#endif

View file

@ -0,0 +1,22 @@
//See the file in the main distribution directory for copyright.
#include "plugin/Plugin.h"
#include "KRB.h"
#include "KRB_TCP.h"
namespace plugin {
namespace Bro_KRB {
class Plugin : public plugin::Plugin {
public:
plugin::Configuration Configure()
{
AddComponent(new ::analyzer::Component("KRB", ::analyzer::krb::KRB_Analyzer::Instantiate));
AddComponent(new ::analyzer::Component("KRB_TCP", ::analyzer::krb_tcp::KRB_Analyzer::Instantiate));
plugin::Configuration config;
config.name = "Bro::KRB";
config.description = "Kerberos analyzer";
return config;
}
} plugin;
}
}

View file

@ -0,0 +1,159 @@
## A Kerberos 5 ``Authentication Server (AS) Request`` as defined
## in :rfc:`4120`. The AS request contains a username of the client
## requesting authentication, and returns an AS reply with an
## encrypted Ticket Granting Ticket (TGT) for that user. The TGT
## can then be used to request further tickets for other services.
##
## See `Wikipedia <http://en.wikipedia.org/wiki/Kerberos_%28protocol%29>`__ for
## more information about the Kerberos protocol.
##
## c: The connection over which this Kerberos message was sent.
##
## msg: A Kerberos KDC request message data structure.
##
## .. bro:see:: krb_as_response krb_tgs_request krb_tgs_response krb_ap_request
## krb_ap_response krb_priv krb_safe krb_cred krb_error
event krb_as_request%(c: connection, msg: KRB::KDC_Request%);
## A Kerberos 5 ``Authentication Server (AS) Response`` as defined
## in :rfc:`4120`. Following the AS request for a user, an AS reply
## contains an encrypted Ticket Granting Ticket (TGT) for that user.
## The TGT can then be used to request further tickets for other services.
##
## See `Wikipedia <http://en.wikipedia.org/wiki/Kerberos_%28protocol%29>`__ for
## more information about the Kerberos protocol.
##
## c: The connection over which this Kerberos message was sent.
##
## msg: A Kerberos KDC reply message data structure.
##
## .. bro:see:: krb_as_request krb_tgs_request krb_tgs_response krb_ap_request
## krb_ap_response krb_priv krb_safe krb_cred krb_error
event krb_as_response%(c: connection, msg: KRB::KDC_Response%);
## A Kerberos 5 ``Ticket Granting Service (TGS) Request`` as defined
## in :rfc:`4120`. Following the Authentication Server exchange, if
## successful, the client now has a Ticket Granting Ticket (TGT). To
## authenticate to a Kerberized service, the client requests a Service
## Ticket, which will be returned in the TGS reply.
##
## See `Wikipedia <http://en.wikipedia.org/wiki/Kerberos_%28protocol%29>`__ for
## more information about the Kerberos protocol.
##
## c: The connection over which this Kerberos message was sent.
##
## msg: A Kerberos KDC request message data structure.
##
## .. bro:see:: krb_as_request krb_as_response krb_tgs_response krb_ap_request
## krb_ap_response krb_priv krb_safe krb_cred krb_error
event krb_tgs_request%(c: connection, msg: KRB::KDC_Request%);
## A Kerberos 5 ``Ticket Granting Service (TGS) Response`` as defined
## in :rfc:`4120`. This message returns a Service Ticket to the client,
## which is encrypted with the service's long-term key, and which the
## client can use to authenticate to that service.
##
## See `Wikipedia <http://en.wikipedia.org/wiki/Kerberos_%28protocol%29>`__ for
## more information about the Kerberos protocol.
##
## c: The connection over which this Kerberos message was sent.
##
## msg: A Kerberos KDC reply message data structure.
##
## .. bro:see:: krb_as_request krb_as_response krb_tgs_request krb_ap_request
## krb_ap_response krb_priv krb_safe krb_cred krb_error
event krb_tgs_response%(c: connection, msg: KRB::KDC_Response%);
## A Kerberos 5 ``Authentication Header (AP) Request`` as defined
## in :rfc:`4120`. This message contains authentication information
## that should be part of the first message in an authenticated
## transaction.
##
## See `Wikipedia <http://en.wikipedia.org/wiki/Kerberos_%28protocol%29>`__ for
## more information about the Kerberos protocol.
##
## c: The connection over which this Kerberos message was sent.
##
## ticket: The Kerberos ticket being used for authentication.
##
## opts: A Kerberos AP options data structure.
##
## .. bro:see:: krb_as_request krb_as_response krb_tgs_request krb_tgs_response
## krb_ap_response krb_priv krb_safe krb_cred krb_error
event krb_ap_request%(c: connection, ticket: KRB::Ticket, opts: KRB::AP_Options%);
## A Kerberos 5 ``Authentication Header (AP) Response`` as defined
## in :rfc:`4120`. This is used if mutual authentication is desired.
## All of the interesting information in here is encrypted, so the event
## doesn't have much useful data, but it's provided in case it's important
## to know that this message was sent.
##
## See `Wikipedia <http://en.wikipedia.org/wiki/Kerberos_%28protocol%29>`__ for
## more information about the Kerberos protocol.
##
## c: The connection over which this Kerberos message was sent.
##
## .. bro:see:: krb_as_request krb_as_response krb_tgs_request krb_tgs_response
## krb_ap_request krb_priv krb_safe krb_cred krb_error
event krb_ap_response%(c: connection%);
## A Kerberos 5 ``Private Message`` as defined in :rfc:`4120`. This
## is a private (encrypted) application message, so the event doesn't
## have much useful data, but it's provided in case it's important to
## know that this message was sent.
##
## See `Wikipedia <http://en.wikipedia.org/wiki/Kerberos_%28protocol%29>`__ for
## more information about the Kerberos protocol.
##
## c: The connection over which this Kerberos message was sent.
##
## is_orig: Whether the originator of the connection sent this message.
##
## .. bro:see:: krb_as_request krb_as_response krb_tgs_request krb_tgs_response
## krb_ap_request krb_ap_response krb_safe krb_cred krb_error
event krb_priv%(c: connection, is_orig: bool%);
## A Kerberos 5 ``Safe Message`` as defined in :rfc:`4120`. This is a
## safe (checksummed) application message.
##
## See `Wikipedia <http://en.wikipedia.org/wiki/Kerberos_%28protocol%29>`__ for
## more information about the Kerberos protocol.
##
## c: The connection over which this Kerberos message was sent.
##
## is_orig: Whether the originator of the connection sent this message.
##
## msg: A Kerberos SAFE message data structure.
##
## .. bro:see:: krb_as_request krb_as_response krb_tgs_request krb_tgs_response
## krb_ap_request krb_ap_response krb_priv krb_cred krb_error
event krb_safe%(c: connection, is_orig: bool, msg: KRB::SAFE_Msg%);
## A Kerberos 5 ``Credential Message`` as defined in :rfc:`4120`. This is
## a private (encrypted) message to forward credentials.
##
## See `Wikipedia <http://en.wikipedia.org/wiki/Kerberos_%28protocol%29>`__ for
## more information about the Kerberos protocol.
##
## c: The connection over which this Kerberos message was sent.
##
## is_orig: Whether the originator of the connection sent this message.
##
## tickets: Tickets obtained from the KDC that are being forwarded.
##
## .. bro:see:: krb_as_request krb_as_response krb_tgs_request krb_tgs_response
## krb_ap_request krb_ap_response krb_priv krb_safe krb_error
event krb_cred%(c: connection, is_orig: bool, tickets: KRB::Ticket_Vector%);
## A Kerberos 5 ``Error Message`` as defined in :rfc:`4120`.
##
## See `Wikipedia <http://en.wikipedia.org/wiki/Kerberos_%28protocol%29>`__ for
## more information about the Kerberos protocol.
##
## c: The connection over which this Kerberos message was sent.
##
## msg: A Kerberos error message data structure.
##
## .. bro:see:: krb_as_request krb_as_response krb_tgs_request krb_tgs_response
## krb_ap_request krb_ap_response krb_priv krb_safe krb_cred
event krb_error%(c: connection, msg: KRB::Error_Msg%);

View file

@ -0,0 +1,383 @@
%header{
RecordVal* proc_krb_kdc_options(const KRB_KDC_Options* opts);
RecordVal* proc_krb_kdc_req_arguments(KRB_KDC_REQ* msg, const BroAnalyzer bro_analyzer);
bool proc_error_arguments(RecordVal* rv, const std::vector<KRB_ERROR_Arg*>* args, int64 error_code);
%}
%code{
RecordVal* proc_krb_kdc_options(const KRB_KDC_Options* opts)
{
RecordVal* rv = new RecordVal(BifType::Record::KRB::KDC_Options);
rv->Assign(0, new Val(opts->forwardable(), TYPE_BOOL));
rv->Assign(1, new Val(opts->forwarded(), TYPE_BOOL));
rv->Assign(2, new Val(opts->proxiable(), TYPE_BOOL));
rv->Assign(3, new Val(opts->proxy(), TYPE_BOOL));
rv->Assign(4, new Val(opts->allow_postdate(), TYPE_BOOL));
rv->Assign(5, new Val(opts->postdated(), TYPE_BOOL));
rv->Assign(6, new Val(opts->renewable(), TYPE_BOOL));
rv->Assign(7, new Val(opts->opt_hardware_auth(), TYPE_BOOL));
rv->Assign(8, new Val(opts->disable_transited_check(), TYPE_BOOL));
rv->Assign(9, new Val(opts->renewable_ok(), TYPE_BOOL));
rv->Assign(10, new Val(opts->enc_tkt_in_skey(), TYPE_BOOL));
rv->Assign(11, new Val(opts->renew(), TYPE_BOOL));
rv->Assign(12, new Val(opts->validate(), TYPE_BOOL));
return rv;
}
RecordVal* proc_krb_kdc_req_arguments(KRB_KDC_REQ* msg, const BroAnalyzer bro_analyzer)
{
RecordVal* rv = new RecordVal(BifType::Record::KRB::KDC_Request);
rv->Assign(0, asn1_integer_to_val(msg->pvno()->data(), TYPE_COUNT));
rv->Assign(1, asn1_integer_to_val(msg->msg_type()->data(), TYPE_COUNT));
if ( msg->padata()->has_padata() )
rv->Assign(2, proc_padata(msg->padata()->padata()->padata(), bro_analyzer, false));
for ( uint i = 0; i < msg->body_args()->size(); ++i )
{
KRB_REQ_Arg* element = (*msg->body_args())[i];
switch ( element->seq_meta()->index() )
{
case 0:
rv->Assign(3, proc_krb_kdc_options(element->data()->options()));
break;
case 1:
rv->Assign(4, GetStringFromPrincipalName(element->data()->principal()));
break;
case 2:
rv->Assign(5, bytestring_to_val(element->data()->realm()->encoding()->content()));
break;
case 3:
rv->Assign(6, GetStringFromPrincipalName(element->data()->sname()));
break;
case 4:
rv->Assign(7, GetTimeFromAsn1(element->data()->from(), 0));
break;
case 5:
rv->Assign(8, GetTimeFromAsn1(element->data()->till(), 0));
break;
case 6:
rv->Assign(9, GetTimeFromAsn1(element->data()->rtime(), 0));
break;
case 7:
rv->Assign(10, asn1_integer_to_val(element->data()->nonce(), TYPE_COUNT));
break;
case 8:
if ( element->data()->etype()->data()->size() )
rv->Assign(11, proc_cipher_list(element->data()->etype()));
break;
case 9:
if ( element->data()->addrs()->addresses()->size() )
rv->Assign(12, proc_host_address_list(element->data()->addrs()));
break;
case 10:
// TODO
break;
case 11:
if ( element->data()->addl_tkts()->tickets()->size() )
rv->Assign(13, proc_tickets(element->data()->addl_tkts()));
break;
default:
break;
}
}
return rv;
}
bool proc_error_arguments(RecordVal* rv, const std::vector<KRB_ERROR_Arg*>* args, int64 error_code )
{
uint ctime_i = 0, stime_i = 0;
int64 ctime_usecs = 0, stime_usecs = 0;
// We need to do a pass first, to see if we have microseconds for the timestamp values, which are optional
for ( uint i = 0; i < args->size(); i++ )
{
switch ( (*args)[i]->seq_meta()->index() )
{
case 2:
ctime_i = i;
break;
case 3:
ctime_usecs = binary_to_int64((*args)[i]->args()->cusec()->encoding()->content());
break;
case 4:
stime_i = i;
break;
case 5:
stime_usecs = binary_to_int64((*args)[i]->args()->susec()->encoding()->content());
break;
default:
break;
}
}
if ( ctime_i )
rv->Assign(2, GetTimeFromAsn1((*args)[ctime_i]->args()->ctime(), ctime_usecs));
if ( stime_i )
rv->Assign(3, GetTimeFromAsn1((*args)[stime_i]->args()->stime(), stime_usecs));
for ( uint i = 0; i < args->size(); ++i )
{
switch ( (*args)[i]->seq_meta()->index() )
{
case 0:
rv->Assign(0, asn1_integer_to_val((*args)[i]->args()->pvno(), TYPE_COUNT));
break;
case 1:
rv->Assign(1, asn1_integer_to_val((*args)[i]->args()->msg_type(), TYPE_COUNT));
break;
// ctime/stime handled above
case 7:
rv->Assign(5, bytestring_to_val((*args)[i]->args()->crealm()->encoding()->content()));
break;
case 8:
rv->Assign(6, GetStringFromPrincipalName((*args)[i]->args()->cname()));
break;
case 9:
rv->Assign(7, bytestring_to_val((*args)[i]->args()->realm()->encoding()->content()));
break;
case 10:
rv->Assign(8, GetStringFromPrincipalName((*args)[i]->args()->sname()));
break;
case 11:
rv->Assign(9, bytestring_to_val((*args)[i]->args()->e_text()->encoding()->content()));
break;
case 12:
if ( error_code == KDC_ERR_PREAUTH_REQUIRED )
rv->Assign(10, proc_padata((*args)[i]->args()->e_data()->padata(), NULL, true));
break;
default:
break;
}
}
return true;
}
%}
refine connection KRB_Conn += {
function proc_krb_kdc_req_msg(msg: KRB_KDC_REQ): bool
%{
bro_analyzer()->ProtocolConfirmation();
if ( ( binary_to_int64(${msg.msg_type.data.content}) == 10 ) && ! krb_as_request )
return false;
if ( ( binary_to_int64(${msg.msg_type.data.content}) == 12 ) && ! krb_tgs_request )
return false;
RecordVal* rv = proc_krb_kdc_req_arguments(${msg}, bro_analyzer());
if ( ( binary_to_int64(${msg.msg_type.data.content}) == 10 ) )
BifEvent::generate_krb_as_request(bro_analyzer(), bro_analyzer()->Conn(), rv);
if ( ( binary_to_int64(${msg.msg_type.data.content}) == 12 ) )
BifEvent::generate_krb_tgs_request(bro_analyzer(), bro_analyzer()->Conn(), rv);
return true;
%}
function proc_krb_kdc_rep_msg(msg: KRB_KDC_REP): bool
%{
bro_analyzer()->ProtocolConfirmation();
if ( ( binary_to_int64(${msg.msg_type.data.content}) == 11 ) && ! krb_as_response )
return false;
if ( ( binary_to_int64(${msg.msg_type.data.content}) == 13 ) && ! krb_tgs_response )
return false;
RecordVal* rv = new RecordVal(BifType::Record::KRB::KDC_Response);
rv->Assign(0, asn1_integer_to_val(${msg.pvno.data}, TYPE_COUNT));
rv->Assign(1, asn1_integer_to_val(${msg.msg_type.data}, TYPE_COUNT));
if ( ${msg.padata.has_padata} )
rv->Assign(2, proc_padata(${msg.padata.padata.padata}, bro_analyzer(), false));
rv->Assign(3, bytestring_to_val(${msg.client_realm.encoding.content}));
rv->Assign(4, GetStringFromPrincipalName(${msg.client_name}));
rv->Assign(5, proc_ticket(${msg.ticket}));
if ( ( binary_to_int64(${msg.msg_type.data.content}) == 11 ) )
BifEvent::generate_krb_as_response(bro_analyzer(), bro_analyzer()->Conn(), rv);
if ( ( binary_to_int64(${msg.msg_type.data.content}) == 13 ) )
BifEvent::generate_krb_tgs_response(bro_analyzer(), bro_analyzer()->Conn(), rv);
return true;
%}
function proc_krb_error_msg(msg: KRB_ERROR_MSG): bool
%{
bro_analyzer()->ProtocolConfirmation();
if ( krb_error )
{
RecordVal* rv = new RecordVal(BifType::Record::KRB::Error_Msg);
proc_error_arguments(rv, ${msg.args1}, 0);
rv->Assign(4, asn1_integer_to_val(${msg.error_code}, TYPE_COUNT));
proc_error_arguments(rv, ${msg.args2}, binary_to_int64(${msg.error_code.encoding.content}));
BifEvent::generate_krb_error(bro_analyzer(), bro_analyzer()->Conn(), rv);
}
return true;
%}
function proc_krb_ap_req_msg(msg: KRB_AP_REQ): bool
%{
bro_analyzer()->ProtocolConfirmation();
if ( krb_ap_request )
{
RecordVal* rv = new RecordVal(BifType::Record::KRB::AP_Options);
rv->Assign(0, new Val(${msg.ap_options.use_session_key}, TYPE_BOOL));
rv->Assign(1, new Val(${msg.ap_options.mutual_required}, TYPE_BOOL));
BifEvent::generate_krb_ap_request(bro_analyzer(), bro_analyzer()->Conn(),
proc_ticket(${msg.ticket}), rv);
}
return true;
%}
function proc_krb_ap_rep_msg(msg: KRB_AP_REP): bool
%{
bro_analyzer()->ProtocolConfirmation();
if ( krb_ap_response )
{
BifEvent::generate_krb_ap_response(bro_analyzer(), bro_analyzer()->Conn());
}
return true;
%}
function proc_krb_safe_msg(msg: KRB_SAFE_MSG): bool
%{
bro_analyzer()->ProtocolConfirmation();
if ( krb_safe )
{
RecordVal* rv = new RecordVal(BifType::Record::KRB::SAFE_Msg);
rv->Assign(0, asn1_integer_to_val(${msg.pvno.data}, TYPE_COUNT));
rv->Assign(1, asn1_integer_to_val(${msg.msg_type.data}, TYPE_COUNT));
uint timestamp_i = 0;
int64 timestamp_usecs = 0;
// We need to do a pass first, to see if we have microseconds for the timestamp values, which are optional
for ( uint i = 0; i < ${msg.safe_body.args}->size(); ++i )
{
switch ( ${msg.safe_body.args[i].seq_meta.index} )
{
case 1:
timestamp_i = i;
break;
case 2:
timestamp_usecs = binary_to_int64(${msg.safe_body.args[i].args.usec.encoding.content});
break;
default:
break;
}
}
if ( timestamp_i )
rv->Assign(4, GetTimeFromAsn1(${msg.safe_body.args[timestamp_i].args.timestamp}, timestamp_usecs));
for ( uint i = 0; i < ${msg.safe_body.args}->size(); ++i )
{
switch ( ${msg.safe_body.args[i].seq_meta.index} )
{
case 0:
rv->Assign(3, bytestring_to_val(${msg.safe_body.args[i].args.user_data.encoding.content}));
break;
case 3:
rv->Assign(5, asn1_integer_to_val(${msg.safe_body.args[i].args.seq_number}, TYPE_COUNT));
break;
case 4:
rv->Assign(6, proc_host_address(${msg.safe_body.args[i].args.sender_addr}));
break;
case 5:
rv->Assign(7, proc_host_address(${msg.safe_body.args[i].args.recp_addr}));
break;
default:
break;
}
}
BifEvent::generate_krb_safe(bro_analyzer(), bro_analyzer()->Conn(), ${msg.is_orig}, rv);
}
return true;
%}
function proc_krb_priv_msg(msg: KRB_PRIV_MSG): bool
%{
bro_analyzer()->ProtocolConfirmation();
if ( krb_priv )
{
BifEvent::generate_krb_priv(bro_analyzer(), bro_analyzer()->Conn(), ${msg.is_orig});
}
return true;
%}
function proc_krb_cred_msg(msg: KRB_CRED_MSG): bool
%{
bro_analyzer()->ProtocolConfirmation();
if ( krb_cred )
{
BifEvent::generate_krb_cred(bro_analyzer(), bro_analyzer()->Conn(), ${msg.is_orig},
proc_tickets(${msg.tickets}));
}
return true;
%}
}
refine typeattr KRB_AS_REQ += &let {
proc: bool = $context.connection.proc_krb_kdc_req_msg(data);
};
refine typeattr KRB_TGS_REQ += &let {
proc: bool = $context.connection.proc_krb_kdc_req_msg(data);
};
refine typeattr KRB_AS_REP += &let {
proc: bool = $context.connection.proc_krb_kdc_rep_msg(data);
};
refine typeattr KRB_TGS_REP += &let {
proc: bool = $context.connection.proc_krb_kdc_rep_msg(data);
};
refine typeattr KRB_AP_REQ += &let {
proc: bool = $context.connection.proc_krb_ap_req_msg(this);
};
refine typeattr KRB_AP_REP += &let {
proc: bool = $context.connection.proc_krb_ap_rep_msg(this);
};
refine typeattr KRB_ERROR_MSG += &let {
proc: bool = $context.connection.proc_krb_error_msg(this);
};
refine typeattr KRB_SAFE_MSG += &let {
proc: bool = $context.connection.proc_krb_safe_msg(this);
};
refine typeattr KRB_PRIV_MSG += &let {
proc: bool = $context.connection.proc_krb_priv_msg(this);
};
refine typeattr KRB_CRED_MSG += &let {
proc: bool = $context.connection.proc_krb_cred_msg(this);
};

View file

@ -0,0 +1,58 @@
%include ../asn1/asn1.pac
%header{
Val* GetTimeFromAsn1(const KRB_Time* atime, int64 usecs);
Val* GetTimeFromAsn1(StringVal* atime, int64 usecs);
%}
%code{
Val* GetTimeFromAsn1(const KRB_Time* atime, int64 usecs)
{
StringVal* atime_bytestring = bytestring_to_val(atime->time());
Val* result = GetTimeFromAsn1(atime_bytestring, usecs);
Unref(atime_bytestring);
return result;
}
Val* GetTimeFromAsn1(StringVal* atime, int64 usecs)
{
time_t lResult = 0;
char lBuffer[17];
char* pBuffer = lBuffer;
size_t lTimeLength = atime->Len();
char * pString = (char *) atime->Bytes();
if ( lTimeLength != 15 && lTimeLength != 17 )
return 0;
if (lTimeLength == 17 )
pString = pString + 2;
memcpy(pBuffer, pString, 15);
*(pBuffer+15) = '\0';
tm lTime;
lTime.tm_sec = ((lBuffer[12] - '0') * 10) + (lBuffer[13] - '0');
lTime.tm_min = ((lBuffer[10] - '0') * 10) + (lBuffer[11] - '0');
lTime.tm_hour = ((lBuffer[8] - '0') * 10) + (lBuffer[9] - '0');
lTime.tm_mday = ((lBuffer[6] - '0') * 10) + (lBuffer[7] - '0');
lTime.tm_mon = (((lBuffer[4] - '0') * 10) + (lBuffer[5] - '0')) - 1;
lTime.tm_year = ((lBuffer[0] - '0') * 1000) + ((lBuffer[1] - '0') * 100) + ((lBuffer[2] - '0') * 10) + (lBuffer[3] - '0') - 1900;
lTime.tm_wday = 0;
lTime.tm_yday = 0;
lTime.tm_isdst = 0;
lResult = timegm(&lTime);
if ( !lResult )
lResult = 0;
return new Val(double(lResult + double(usecs/100000.0)), TYPE_TIME);
}
%}

View file

@ -0,0 +1,27 @@
# Defined in RFC 4120
enum KRBMessageTypes {
AS_REQ = 10,
AS_REP = 11,
TGS_REQ = 12,
TGS_REP = 13,
AP_REQ = 14,
AP_REP = 15,
KRB_SAFE = 20,
KRB_PRIV = 21,
KRB_CRED = 22,
KRB_ERROR = 30,
};
# Defined by IANA in Kerberos Parameters - Pre-authentication and Typed Data
enum KRBPADataTypes {
PA_TGS_REQ = 1,
PA_ENC_TIMESTAMP = 2,
PA_PW_SALT = 3,
PA_PW_AS_REQ = 16,
PA_PW_AS_REP = 17,
};
# Defined in RFC 4120
enum KRBErrorCodes {
KDC_ERR_PREAUTH_REQUIRED = 25,
};

View file

@ -0,0 +1,212 @@
# Kerberos pre-authentication data is a significant piece of the complexity,
# so we're splitting this off
%extern{
#include "file_analysis/Manager.h"
%}
%header{
VectorVal* proc_padata(const KRB_PA_Data_Sequence* data, const BroAnalyzer bro_analyzer, bool is_error);
%}
%code{
VectorVal* proc_padata(const KRB_PA_Data_Sequence* data, const BroAnalyzer bro_analyzer, bool is_error)
{
VectorVal* vv = new VectorVal(internal_type("KRB::Type_Value_Vector")->AsVectorType());
if ( ! data->data()->has_padata() )
return vv;
for ( uint i = 0; i < data->data()->padata_elems()->size(); ++i)
{
KRB_PA_Data* element = (*data->data()->padata_elems())[i];
int64 data_type = element->data_type();
if ( is_error && ( data_type == PA_PW_AS_REQ || data_type == PA_PW_AS_REP ) )
data_type = 0;
switch( data_type )
{
case PA_TGS_REQ:
// will be generated as separate event
break;
case PA_ENC_TIMESTAMP:
// encrypted timestamp is unreadable
break;
case PA_PW_SALT:
{
RecordVal * type_val = new RecordVal(BifType::Record::KRB::Type_Value);
type_val->Assign(0, new Val(element->data_type(), TYPE_COUNT));
type_val->Assign(1, bytestring_to_val(element->pa_data_element()->pa_pw_salt()->encoding()->content()));
vv->Assign(vv->Size(), type_val);
break;
}
case PA_PW_AS_REQ:
{
const bytestring& cert = element->pa_data_element()->pa_pk_as_req()->cert();
ODesc common;
common.AddRaw("Analyzer::ANALYZER_KRB");
common.Add(bro_analyzer->Conn()->StartTime());
// Request means is_orig=T
common.AddRaw("T", 1);
bro_analyzer->Conn()->IDString(&common);
ODesc file_handle;
file_handle.Add(common.Description());
file_handle.Add(0);
string file_id = file_mgr->HashHandle(file_handle.Description());
file_mgr->DataIn(reinterpret_cast<const u_char*>(cert.data()),
cert.length(), bro_analyzer->GetAnalyzerTag(),
bro_analyzer->Conn(), true, file_id);
file_mgr->EndOfFile(file_id);
break;
}
case PA_PW_AS_REP:
{
const bytestring& cert = element->pa_data_element()->pa_pk_as_rep()->cert();
ODesc common;
common.AddRaw("Analyzer::ANALYZER_KRB");
common.Add(bro_analyzer->Conn()->StartTime());
// Response means is_orig=F
common.AddRaw("F", 1);
bro_analyzer->Conn()->IDString(&common);
ODesc file_handle;
file_handle.Add(common.Description());
file_handle.Add(1);
string file_id = file_mgr->HashHandle(file_handle.Description());
file_mgr->DataIn(reinterpret_cast<const u_char*>(cert.data()),
cert.length(), bro_analyzer->GetAnalyzerTag(),
bro_analyzer->Conn(), false, file_id);
file_mgr->EndOfFile(file_id);
break;
}
default:
{
if ( ! is_error && element->pa_data_element()->unknown().length() )
{
RecordVal * type_val = new RecordVal(BifType::Record::KRB::Type_Value);
type_val->Assign(0, new Val(element->data_type(), TYPE_COUNT));
type_val->Assign(1, bytestring_to_val(element->pa_data_element()->unknown()));
vv->Assign(vv->Size(), type_val);
}
break;
}
}
}
return vv;
}
%}
# Basic structure:
# 1) In KDC_REQ/KDC_REP packets, the PA_Data is optional and needs a bit of "lookahead."
# KRB_PA_Data_Optional -> KRB_PA_Data_Optional_Contents -> KRB_PA_Data_Sequence
#
# 2) Once we get to the KRB_PA_Data_Sequence level:
# KRB_PA_Data_Sequence -> KRB_PA_Data_Container -> KRB_PA_Data -> KRB_PA_Data_Element
# Encapsulating header #1 for KDC_REQ/KDC_REP packets where the PADATA is optional.
type KRB_PA_Data_Optional(is_orig: bool, pkt_type: uint8, desired_index: uint8) = record {
first_meta : ASN1EncodingMeta;
padata : KRB_PA_Data_Optional_Contents(is_orig, has_padata, pkt_type, first_meta.length);
next_meta : ASN1OptionalEncodingMeta(has_padata, first_meta);
} &let {
has_padata : bool = first_meta.index == desired_index;
};
# Encapsulating header #2 for KDC_REQ/KDC_REP packets where the PADATA is optional.
#
# Note: Split off due to a BinPAC bug
type KRB_PA_Data_Optional_Contents(is_orig: bool, is_present: bool, pkt_type: uint8, length: uint64) = case is_present of {
true -> padata : KRB_PA_Data_Sequence(is_orig, pkt_type) &length=length;
false -> none : empty;
};
# This is our main type
type KRB_PA_Data_Sequence(is_orig: bool, pkt_type: uint8) = record {
meta : ASN1EncodingMeta;
data : KRB_PA_Data_Container(is_orig, pkt_type, meta.tag, meta.length);
};
# The data in KRB_PA_Data_Sequence is usually (and supposed to be) a sequence, which we'll parse,
# but is sometimes an octet string. We'll grab that but ignore it.
#
# Note: This is a separate type due to a BinPAC bug.
type KRB_PA_Data_Container(is_orig: bool, pkt_type: uint8, tag: uint8, length: uint64) = case tag of {
ASN1_SEQUENCE_TAG -> padata_elems : KRB_PA_Data(is_orig, pkt_type)[];
default -> unknown : bytestring &length=length;
} &let {
has_padata: bool = (tag == ASN1_SEQUENCE_TAG);
};
# The pre-auth data sequence.
#
# Note: Error packets don't have pre-auth data, they just advertise which mechanisms they support.
type KRB_PA_Data(is_orig: bool, pkt_type: uint8) = record {
seq_meta : ASN1EncodingMeta;
pa_data_type : SequenceElement(true);
pa_data_elem_meta : ASN1EncodingMeta;
have_data : case pkt_type of {
KRB_ERROR -> pa_data_placeholder: bytestring &length=pa_data_elem_meta.length;
default -> pa_data_element : KRB_PA_Data_Element(is_orig, data_type, pa_data_elem_meta.length);
} &requires(data_type);
} &let {
data_type: int64 = binary_to_int64(pa_data_type.data.content);
};
# Each pre-auth element
type KRB_PA_Data_Element(is_orig: bool, type: int64, length: uint64) = case type of {
PA_TGS_REQ -> pa_tgs_req : KRB_AP_REQ(is_orig);
PA_PW_SALT -> pa_pw_salt : ASN1OctetString;
PA_PW_AS_REQ -> pa_pk_as_req : KRB_PA_PK_AS_Req &length=length;
PA_PW_AS_REP -> pa_pk_as_rep : KRB_PA_PK_AS_Rep &length=length;
default -> unknown : bytestring &length=length;
};
# The PKINIT certificate structure for a request
type KRB_PA_PK_AS_Req = record {
string_meta : ASN1EncodingMeta;
seq_meta1 : ASN1EncodingMeta;
elem_0_meta1 : ASN1EncodingMeta;
seq_meta2 : ASN1EncodingMeta;
oid : ASN1Encoding;
elem_0_meta2 : ASN1EncodingMeta;
seq_meta3 : ASN1EncodingMeta;
version : ASN1Encoding;
digest_algs : ASN1Encoding;
signed_data : ASN1Encoding;
cert_meta : ASN1EncodingMeta;
cert : bytestring &length=cert_meta.length;
# Ignore everything else
: bytestring &restofdata &transient;
};
# The PKINIT certificate structure for a reply
type KRB_PA_PK_AS_Rep = record {
string_meta : ASN1EncodingMeta;
elem_0_meta1 : ASN1EncodingMeta;
seq_meta1 : ASN1EncodingMeta;
elem_0_meta2 : ASN1EncodingMeta;
seq_meta2 : ASN1EncodingMeta;
oid : ASN1Encoding;
elem_0_meta3 : ASN1EncodingMeta;
seq_meta3 : ASN1EncodingMeta;
version : ASN1Encoding;
digest_algs : ASN1Encoding;
signed_data : ASN1Encoding;
cert_meta : ASN1EncodingMeta;
cert : bytestring &length=cert_meta.length;
# Ignore everything else
: bytestring &restofdata &transient;
};

View file

@ -0,0 +1,240 @@
# ASN1 parsing
%include krb-asn1.pac
# Constants
%include krb-defs.pac
# Basic types
%include krb-types.pac
# Preauth data parsing
%include krb-padata.pac
# KRB over TCP is the same as over UDP, but prefixed with a uint32 denoting the size
type KRB_PDU_TCP(is_orig: bool) = record {
size : uint32;
pdu : KRB_PDU(is_orig);
} &length=size+4 &byteorder=bigendian;
type KRB_PDU(is_orig: bool) = record {
app_meta : ASN1EncodingMeta;
msg_type : case (app_meta.tag - ASN1_APP_TAG_OFFSET) of {
AS_REQ -> as_req : KRB_AS_REQ(is_orig);
AS_REP -> as_rep : KRB_AS_REP(is_orig);
TGS_REQ -> tgs_req : KRB_TGS_REQ(is_orig);
TGS_REP -> tgs_rep : KRB_TGS_REP(is_orig);
AP_REQ -> ap_req : KRB_AP_REQ(is_orig);
AP_REP -> ap_rep : KRB_AP_REP(is_orig);
KRB_SAFE -> krb_safe : KRB_SAFE_MSG(is_orig);
KRB_PRIV -> krb_priv : KRB_PRIV_MSG(is_orig);
KRB_CRED -> krb_cred : KRB_CRED_MSG(is_orig);
KRB_ERROR -> krb_error: KRB_ERROR_MSG(is_orig);
};
} &byteorder=bigendian;
type KRB_AS_REQ(is_orig: bool) = record {
data: KRB_KDC_REQ(is_orig, AS_REQ);
};
type KRB_TGS_REQ(is_orig: bool) = record {
data: KRB_KDC_REQ(is_orig, TGS_REQ);
};
type KRB_AS_REP(is_orig: bool) = record {
data: KRB_KDC_REP(is_orig, AS_REP);
};
type KRB_TGS_REP(is_orig: bool) = record {
data: KRB_KDC_REP(is_orig, TGS_REP);
};
### A Kerberos ticket-granting-service or authentication-service request
type KRB_KDC_REQ(is_orig: bool, pkt_type: uint8) = record {
seq_meta : ASN1EncodingMeta;
pvno : SequenceElement(true);
msg_type : SequenceElement(true);
padata : KRB_PA_Data_Optional(is_orig, pkt_type, 3);
body_meta : ASN1EncodingMeta;
body_args : KRB_REQ_Arg[];
};
type KRB_REQ_Arg = record {
seq_meta : ASN1EncodingMeta;
data : KRB_REQ_Arg_Data(seq_meta.index) &length=seq_meta.length;
};
type KRB_REQ_Arg_Data(index: uint8) = case index of {
0 -> options : KRB_KDC_Options;
1 -> principal : KRB_Principal_Name;
2 -> realm : ASN1OctetString;
3 -> sname : KRB_Principal_Name;
4 -> from : KRB_Time;
5 -> till : KRB_Time;
6 -> rtime : KRB_Time;
7 -> nonce : ASN1Integer;
8 -> etype : Array;
9 -> addrs : KRB_Host_Addresses;
10 -> auth_data : ASN1OctetString;
11 -> addl_tkts : KRB_Ticket_Sequence;
default -> unknown : bytestring &restofdata;
};
type KRB_KDC_Options = record {
meta : ASN1EncodingMeta;
pad : uint8;
flags : uint32;
} &let {
reserved : bool = (flags & 0x80000000) > 0;
forwardable : bool = (flags & 0x40000000) > 0;
forwarded : bool = (flags & 0x20000000) > 0;
proxiable : bool = (flags & 0x10000000) > 0;
proxy : bool = (flags & 0x8000000) > 0;
allow_postdate : bool = (flags & 0x4000000) > 0;
postdated : bool = (flags & 0x2000000) > 0;
unused7 : bool = (flags & 0x1000000) > 0;
renewable : bool = (flags & 0x800000) > 0;
unused9 : bool = (flags & 0x400000) > 0;
unused10 : bool = (flags & 0x200000) > 0;
opt_hardware_auth : bool = (flags & 0x100000) > 0;
unused12 : bool = (flags & 0x80000) > 0;
unused13 : bool = (flags & 0x40000) > 0;
# ...
unused15 : bool = (flags & 0x10000) > 0;
# ...
disable_transited_check : bool = (flags & 0x10) > 0;
renewable_ok : bool = (flags & 0x8) > 0;
enc_tkt_in_skey : bool = (flags & 0x4) > 0;
renew : bool = (flags & 0x2) > 0;
validate : bool = (flags & 0x1) > 0;
};
### KDC_REP
type KRB_KDC_REP(is_orig: bool, pkt_type: uint8) = record {
seq_meta : ASN1EncodingMeta;
pvno : SequenceElement(true);
msg_type : SequenceElement(true);
padata : KRB_PA_Data_Optional(is_orig, pkt_type, 2);
client_realm: ASN1OctetString &length=padata.next_meta.length;
cname_meta : ASN1EncodingMeta;
client_name : KRB_Principal_Name &length=cname_meta.length;
ticket : KRB_Ticket(true);
enc_part : KRB_Encrypted_Data_in_Seq;
};
### AP_REQ
type KRB_AP_REQ(is_orig: bool) = record {
string_meta : ASN1EncodingMeta;
app_meta : ASN1EncodingMeta;
seq_meta : ASN1EncodingMeta;
pvno : SequenceElement(true);
msg_type : SequenceElement(true);
ap_options : KRB_AP_Options;
ticket : KRB_Ticket(true);
enc_part : KRB_Encrypted_Data_in_Seq;
};
type KRB_AP_Options = record {
meta : SequenceElement(false);
flags : uint32;
: padding[1];
} &let {
reserved : bool = (flags & 0x80000000) > 0;
use_session_key : bool = (flags & 0x40000000) > 0;
mutual_required : bool = (flags & 0x20000000) > 0;
};
### AP_REP
type KRB_AP_REP(is_orig: bool) = record {
pvno : SequenceElement(true);
msg_type: SequenceElement(true);
enc_part: KRB_Encrypted_Data_in_Seq;
};
### KRB_ERROR
type KRB_ERROR_MSG(is_orig: bool) = record {
seq_meta : ASN1EncodingMeta;
args1 : KRB_ERROR_Arg(is_orig, 0)[] &until ($element.process_in_parent);
error_code : ASN1Integer;
args2 : KRB_ERROR_Arg(is_orig, binary_to_int64(error_code.encoding.content))[];
};
type KRB_ERROR_Arg(is_orig: bool, error_code: int64) = record {
seq_meta: ASN1EncodingMeta;
args : KRB_ERROR_Arg_Data(is_orig, seq_meta.index, error_code) &length=arg_length;
} &let {
process_in_parent : bool = seq_meta.index == 6;
arg_length : uint64 = ( process_in_parent ? 0 : seq_meta.length);
};
type KRB_ERROR_Arg_Data(is_orig: bool, index: uint8, error_code: int64) = case index of {
0 -> pvno : ASN1Integer;
1 -> msg_type : ASN1Integer;
2 -> ctime : KRB_Time;
3 -> cusec : ASN1Integer;
4 -> stime : KRB_Time;
5 -> susec : ASN1Integer;
6 -> err_code : empty;
7 -> crealm : ASN1OctetString;
8 -> cname : KRB_Principal_Name;
9 -> realm : ASN1OctetString;
10 -> sname : KRB_Principal_Name;
11 -> e_text : ASN1OctetString;
12 -> e_data : KRB_ERROR_E_Data(is_orig, error_code);
};
type KRB_ERROR_E_Data(is_orig: bool, error_code: uint64) = case ( error_code == KDC_ERR_PREAUTH_REQUIRED ) of {
true -> padata : KRB_PA_Data_Sequence(is_orig, KRB_ERROR);
false -> unknown : bytestring &restofdata;
};
### KRB_SAFE
type KRB_SAFE_MSG(is_orig: bool) = record {
pvno : SequenceElement(true);
msg_type : SequenceElement(true);
safe_body: KRB_SAFE_Body;
checksum : KRB_Checksum;
};
type KRB_SAFE_Body = record {
seq_meta: ASN1EncodingMeta;
args : KRB_SAFE_Arg[];
};
type KRB_SAFE_Arg = record {
seq_meta: ASN1EncodingMeta;
args : KRB_SAFE_Arg_Data(seq_meta.index) &length=seq_meta.length;
};
type KRB_SAFE_Arg_Data(index: uint8) = case index of {
0 -> user_data : ASN1OctetString;
1 -> timestamp : KRB_Time;
2 -> usec : ASN1Integer;
3 -> seq_number : ASN1Integer;
4 -> sender_addr: KRB_Host_Address;
5 -> recp_addr : KRB_Host_Address;
};
### KRB_PRIV
type KRB_PRIV_MSG(is_orig: bool) = record {
pvno : SequenceElement(true);
msg_type: SequenceElement(true);
enc_part: KRB_Encrypted_Data_in_Seq;
};
### KRB_CRED
type KRB_CRED_MSG(is_orig: bool) = record {
pvno : SequenceElement(true);
msg_type : SequenceElement(true);
tkts_meta: SequenceElement(false);
tickets : KRB_Ticket_Sequence;
enc_part : KRB_Encrypted_Data_in_Seq;
};

View file

@ -0,0 +1,171 @@
# Fundamental KRB types
%header{
Val* GetStringFromPrincipalName(const KRB_Principal_Name* pname);
VectorVal* proc_cipher_list(const Array* list);
VectorVal* proc_host_address_list(const KRB_Host_Addresses* list);
RecordVal* proc_host_address(const KRB_Host_Address* addr);
VectorVal* proc_tickets(const KRB_Ticket_Sequence* list);
RecordVal* proc_ticket(const KRB_Ticket* ticket);
%}
%code{
Val* GetStringFromPrincipalName(const KRB_Principal_Name* pname)
{
if ( pname->data()->size() == 1 )
return bytestring_to_val(pname->data()[0][0]->encoding()->content());
if ( pname->data()->size() == 2 )
return new StringVal(fmt("%s/%s", (char *) pname->data()[0][0]->encoding()->content().begin(), (char *)pname->data()[0][1]->encoding()->content().begin()));
return new StringVal("unknown");
}
VectorVal* proc_cipher_list(const Array* list)
{
VectorVal* ciphers = new VectorVal(internal_type("index_vec")->AsVectorType());
for ( uint i = 0; i < list->data()->size(); ++i )
ciphers->Assign(ciphers->Size(), asn1_integer_to_val((*list->data())[i], TYPE_COUNT));
return ciphers;
}
VectorVal* proc_host_address_list(const KRB_Host_Addresses* list)
{
VectorVal* addrs = new VectorVal(internal_type("KRB::Host_Address_Vector")->AsVectorType());
for ( uint i = 0; i < list->addresses()->size(); ++i )
{
addrs->Assign(addrs->Size(), proc_host_address((*list->addresses())[i]));
}
return addrs;
}
RecordVal* proc_host_address(const KRB_Host_Address* addr)
{
RecordVal* rv = new RecordVal(BifType::Record::KRB::Host_Address);
switch ( binary_to_int64(addr->addr_type()->encoding()->content()) )
{
case 2:
rv->Assign(0, new AddrVal(IPAddr(IPv4,
(const uint32_t*) c_str(addr->address()->data()->content()),
IPAddr::Network)));
break;
case 24:
rv->Assign(0, new AddrVal(IPAddr(IPv6,
(const uint32_t*) c_str(addr->address()->data()->content()),
IPAddr::Network)));
break;
case 20:
rv->Assign(1, bytestring_to_val(addr->address()->data()->content()));
break;
default:
RecordVal* unk = new RecordVal(BifType::Record::KRB::Type_Value);
unk->Assign(0, asn1_integer_to_val(addr->addr_type(), TYPE_COUNT));
unk->Assign(1, bytestring_to_val(addr->address()->data()->content()));
rv->Assign(2, unk);
break;
}
return rv;
}
VectorVal* proc_tickets(const KRB_Ticket_Sequence* list)
{
VectorVal* tickets = new VectorVal(internal_type("KRB::Ticket_Vector")->AsVectorType());
for ( uint i = 0; i < list->tickets()->size(); ++i )
{
KRB_Ticket* element = (*list->tickets())[i];
tickets->Assign(tickets->Size(), proc_ticket(element));
}
return tickets;
}
RecordVal* proc_ticket(const KRB_Ticket* ticket)
{
RecordVal* rv = new RecordVal(BifType::Record::KRB::Ticket);
rv->Assign(0, asn1_integer_to_val(ticket->tkt_vno()->data(), TYPE_COUNT));
rv->Assign(1, bytestring_to_val(ticket->realm()->data()->content()));
rv->Assign(2, GetStringFromPrincipalName(ticket->sname()));
rv->Assign(3, asn1_integer_to_val(ticket->enc_part()->data()->etype()->data(), TYPE_COUNT));
return rv;
}
%}
type KRB_Principal_Name = record {
seq_meta : ASN1EncodingMeta;
name_meta : ASN1EncodingMeta;
name_type : ASN1Integer;
seq_meta_1: ASN1EncodingMeta;
seq_meta_2: ASN1EncodingMeta;
data : ASN1OctetString[];
};
type KRB_Time = record {
meta: ASN1EncodingMeta;
time: bytestring &restofdata;
};
type KRB_Host_Addresses = record {
seq_meta : ASN1EncodingMeta;
addresses: KRB_Host_Address[];
};
type KRB_Host_Address = record {
addr_type_meta : SequenceElement(false);
addr_type : ASN1Integer;
address : SequenceElement(true);
};
type KRB_Ticket(in_sequence: bool) = record {
have_seq : case in_sequence of {
true -> meta: ASN1EncodingMeta;
false -> none: empty;
};
app_meta : ASN1EncodingMeta;
seq_meta : ASN1EncodingMeta;
tkt_vno : SequenceElement(true);
realm : SequenceElement(true);
sname_meta: ASN1EncodingMeta;
sname : KRB_Principal_Name &length=sname_meta.length;
enc_part : KRB_Encrypted_Data_in_Seq;
};
type KRB_Ticket_Sequence = record {
seq_meta : ASN1EncodingMeta;
tickets : KRB_Ticket(false)[] &length=seq_meta.length;
};
type KRB_Encrypted_Data_in_Seq = record {
index_meta : ASN1EncodingMeta;
data : KRB_Encrypted_Data &length=index_meta.length;
};
type KRB_Encrypted_Data = record {
seq_meta : ASN1EncodingMeta;
etype : SequenceElement(true);
kvno_meta : ASN1EncodingMeta;
case_kvno : case have_kvno of {
true -> kvno : ASN1Integer;
false -> none : empty;
};
grab_next_meta : case have_kvno of {
true -> next_meta: ASN1EncodingMeta;
false -> none_meta: empty;
};
ciphertext : bytestring &length=have_kvno ? next_meta.length : kvno_meta.length;
} &let {
have_kvno : bool = kvno_meta.index == 1;
};
type KRB_Checksum = record {
checksum_type: SequenceElement(true);
checksum : SequenceElement(true);
};

View file

@ -0,0 +1,25 @@
%include binpac.pac
%include bro.pac
%extern{
#include "types.bif.h"
#include "events.bif.h"
%}
analyzer KRB withcontext {
connection: KRB_Conn;
flow: KRB_Flow;
};
connection KRB_Conn(bro_analyzer: BroAnalyzer) {
upflow = KRB_Flow(true);
downflow = KRB_Flow(false);
};
%include krb-protocol.pac
flow KRB_Flow(is_orig: bool) {
datagram = KRB_PDU(is_orig) withcontext(connection, this);
};
%include krb-analyzer.pac

View file

@ -0,0 +1,25 @@
%include binpac.pac
%include bro.pac
%extern{
#include "types.bif.h"
#include "events.bif.h"
%}
analyzer KRB_TCP withcontext {
connection: KRB_Conn;
flow: KRB_Flow;
};
connection KRB_Conn(bro_analyzer: BroAnalyzer) {
upflow = KRB_Flow(true);
downflow = KRB_Flow(false);
};
%include krb-protocol.pac
flow KRB_Flow(is_orig: bool) {
flowunit = KRB_PDU_TCP(is_orig) withcontext(connection, this);
};
%include krb-analyzer.pac

View file

@ -0,0 +1,17 @@
module KRB;
type Error_Msg: record;
type SAFE_Msg: record;
type KDC_Options: record;
type AP_Options: record;
type Type_Value: record;
type Ticket: record;
type Ticket_Vector: vector;
type Host_Address: record;
type KDC_Request: record;
type KDC_Response: record;
module GLOBAL;

View file

@ -1,16 +0,0 @@
# This is not an actual analyzer, but used by the core. We still
# maintain it here along with the other analyzers because conceptually
# it's also parsing a protocol just like them. The current structure
# is merely a left-over from when this code was written.
include(BroPlugin)
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
bro_plugin_begin(Bro NetFlow)
bro_plugin_cc(Plugin.cc)
bro_plugin_bif(events.bif)
bro_plugin_pac(netflow.pac netflow-protocol.pac netflow-analyzer.pac)
bro_plugin_end()

View file

@ -1,18 +0,0 @@
## Generated for a received NetFlow v5 header. Bro's NetFlow processor raises
## this event whenever it either receives a NetFlow header on the port it's
## listening on, or reads one from a trace file.
##
## h: The parsed NetFlow header.
##
## .. bro:see:: netflow_v5_record
event netflow_v5_header%(h: nf_v5_header%);
## Generated for a received NetFlow v5 record. Bro's NetFlow processor raises
## this event whenever it either receives a NetFlow record on the port it's
## listening on, or reads one from a trace file.
##
## r: The parsed NetFlow record.
##
## .. bro:see:: netflow_v5_record
event netflow_v5_record%(r: nf_v5_record%);

View file

@ -1,174 +0,0 @@
# Code written by Bernhard Ager (2007).
analyzer NetFlow withcontext {
analyzer: NetFlow_Analyzer;
flow: NetFlow_Flow;
}
analyzer NetFlow_Analyzer {
downflow = NetFlow_Flow;
upflow = NetFlow_Flow;
};
flow NetFlow_Flow {
datagram = NetFlowPacket withcontext(connection, this);
%member{
RecordType* nf_v5_header_type;
RecordType* nf_v5_record_type;
RecordType* nfheader_id_type;
char* identifier;
uint32 exporter_ip;
uint32 uptime;
double export_time;
bro_uint_t pdu_id;
%}
%init{
nf_v5_header_type =
internal_type("nf_v5_header")->AsRecordType();
nf_v5_record_type =
internal_type("nf_v5_record")->AsRecordType();
nfheader_id_type =
internal_type("nfheader_id")->AsRecordType();
identifier = NULL;
exporter_ip = 0;
uptime = 0;
export_time = 0;
pdu_id = 0;
%}
# %cleanup does not only put the cleanup code into the destructor,
# but also at the end of the catch clause in NewData(). This is
# different from the documentation at
# http://www.bro.org/wiki/index.php/BinPAC_Userguide#.25cleanup.7B....25.7D
#
# Unfortunately this means that we cannot clean up the identifier
# string. Note that IOSource destructors seemingly are never
# called anyway.
#
# %cleanup{
# delete[] identifier;
# %}
function set_exporter_ip(exporter_ip: uint32): bool
%{
this->exporter_ip = exporter_ip;
return true;
%}
function set_identifier(idf: const_charptr): bool
%{
if ( identifier )
delete[] identifier;
identifier = new char[strlen(idf) + 1];
strcpy(identifier, idf);
return true;
%}
function deliver_v5_header(count: uint16, sysuptime: uint32,
unix_secs: uint32, unix_nsecs: uint32,
flow_seq: uint32, eng_type: uint8,
eng_id: uint8, sample_int: uint16): bool
%{
uptime = sysuptime;
export_time = unix_secs + unix_nsecs / 1e9;
++pdu_id;
if ( ! ::netflow_v5_header )
return false;
RecordVal* nfheader = new RecordVal(nfheader_id_type);
nfheader->Assign(0, new StringVal(identifier));
nfheader->Assign(1, new Val(pdu_id, TYPE_COUNT));
RecordVal* v5header = new RecordVal(nf_v5_header_type);
v5header->Assign(0, nfheader);
v5header->Assign(1, new Val(count, TYPE_COUNT));
v5header->Assign(2, new IntervalVal(sysuptime, Milliseconds));
v5header->Assign(3, new Val(export_time, TYPE_TIME));
v5header->Assign(4, new Val(flow_seq, TYPE_COUNT));
v5header->Assign(5, new Val(eng_type, TYPE_COUNT));
v5header->Assign(6, new Val(eng_id, TYPE_COUNT));
v5header->Assign(7, new Val(sample_int, TYPE_COUNT));
v5header->Assign(8, new AddrVal(exporter_ip));
val_list* vl = new val_list;
vl->append(v5header);
mgr.QueueEvent(netflow_v5_header, vl);
return true;
%}
function deliver_v5_record(srcaddr: uint32, dstaddr: uint32,
nexthop: uint32, input: uint16, output: uint16,
dPkts: uint32, dOctets: uint32,
first: uint32, last: uint32,
srcport: uint16, dstport: uint16,
tcp_flags: uint8, prot: uint8, tos: uint8,
src_as: uint16, dst_as: uint16,
src_mask: uint8, dst_mask: uint8): bool
%{
if ( ! ::netflow_v5_record )
return false;
TransportProto proto = TRANSPORT_UNKNOWN;
switch ( prot ) {
case 1: proto = TRANSPORT_ICMP; break;
case 6: proto = TRANSPORT_TCP; break;
case 17: proto = TRANSPORT_UDP; break;
}
RecordVal* connid = new RecordVal(conn_id);
connid->Assign(0, new AddrVal(htonl(srcaddr)));
connid->Assign(1, new PortVal(srcport, proto));
connid->Assign(2, new AddrVal(htonl(dstaddr)));
connid->Assign(3, new PortVal(dstport, proto));
RecordVal* nfheader = new RecordVal(nfheader_id_type);
nfheader->Assign(0, new StringVal(identifier));
nfheader->Assign(1, new Val(pdu_id, TYPE_COUNT));
RecordVal* v5record = new RecordVal(nf_v5_record_type);
v5record->Assign(0, nfheader);
v5record->Assign(1, connid);
v5record->Assign(2, new AddrVal(htonl(nexthop)));
v5record->Assign(3, new Val(input, TYPE_COUNT));
v5record->Assign(4, new Val(output, TYPE_COUNT));
v5record->Assign(5, new Val(dPkts, TYPE_COUNT));
v5record->Assign(6, new Val(dOctets, TYPE_COUNT));
// Overflows are handled correctly by using 32 bit
// unsigned integer arithmetic.
double c_first = export_time - (uptime - first) * Milliseconds;
double c_last = export_time - (uptime - last) * Milliseconds;
v5record->Assign(7, new Val(c_first, TYPE_TIME));
v5record->Assign(8, new Val(c_last, TYPE_TIME));
v5record->Assign(9,
new Val((tcp_flags & TH_FIN) != 0, TYPE_BOOL));
v5record->Assign(10,
new Val((tcp_flags & TH_SYN) != 0, TYPE_BOOL));
v5record->Assign(11,
new Val((tcp_flags & TH_RST) != 0, TYPE_BOOL));
v5record->Assign(12,
new Val((tcp_flags & TH_PUSH) != 0, TYPE_BOOL));
v5record->Assign(13,
new Val((tcp_flags & TH_ACK) != 0, TYPE_BOOL));
v5record->Assign(14,
new Val((tcp_flags & TH_URG) != 0, TYPE_BOOL));
v5record->Assign(15, new Val(prot, TYPE_COUNT));
v5record->Assign(16, new Val(tos, TYPE_COUNT));
v5record->Assign(17, new Val(src_as, TYPE_COUNT));
v5record->Assign(18, new Val(dst_as, TYPE_COUNT));
v5record->Assign(19, new Val(src_mask, TYPE_COUNT));
v5record->Assign(20, new Val(dst_mask, TYPE_COUNT));
val_list* vl = new val_list;
vl->append(v5record);
mgr.QueueEvent(netflow_v5_record, vl);
return true;
%}
};

View file

@ -1,89 +0,0 @@
# Code written by Bernhard Ager (2007).
type NetFlowPacket = record {
# Count and version are the first two fields, at least for
# versions 1, 5, 7, 8 and 9.
version: uint16;
# This does not generate any code in current binpac.
count: uint16 &check(count <= 30);
header: NFHeader(version, count);
records: NFRecord(version)[count];
} &byteorder = bigendian;
type NFHeader(version: uint16, count: uint16) = case version of {
5 -> v5header: NFv5HeaderRest(count);
9 -> v9header: NFv9HeaderRest(count);
# default -> string: bytestring &restofdata &transient;
};
type NFv5HeaderRest(count: uint16) = record {
sysuptime: uint32;
unix_secs: uint32;
unix_nsecs: uint32;
flow_seq: uint32;
eng_type: uint8;
eng_id: uint8;
sample_int: uint16;
} &let {
delivered: bool =
$context.flow.deliver_v5_header(count, sysuptime,
unix_secs, unix_nsecs,
flow_seq, eng_type,
eng_id, sample_int);
};
type NFv9HeaderRest(count: uint16) = record {
sysuptime: uint32;
unix_secs: uint32;
pack_seq: uint32;
src_id: uint32;
};
# We only handle version 5 and 9. Others will throw a parsing exception.
type NFRecord(nf_version: uint32) = case nf_version of {
5 -> v5: NFv5Record;
9 -> v9: NFv9Record;
};
type NFv5Record = record {
srcaddr: uint32;
dstaddr: uint32;
nexthop: uint32;
input: uint16;
output: uint16;
dPkts: uint32;
dOctets: uint32;
first: uint32;
last: uint32;
srcport: uint16;
dstport: uint16;
: uint8; # PAD1
tcp_flags: uint8;
prot: uint8;
tos: uint8;
src_as: uint16;
dst_as: uint16;
src_mask: uint8;
dst_mask: uint8;
: uint16; # PAD2
} &let {
delivered: bool =
$context.flow.deliver_v5_record(srcaddr, dstaddr,
nexthop, input, output,
dPkts, dOctets, first,
last, srcport, dstport,
tcp_flags, prot, tos,
src_as, dst_as,
src_mask, dst_mask);
};
# Works for both template and data flow sets. Data parsing will have
# to be done externally - no event generation yet. We need sample
# flow data to implement that.
type NFv9Record = record {
flowset_id: uint32;
length: uint32;
data: bytestring &length = length - 8;
};

View file

@ -1,13 +0,0 @@
# Code written by Bernhard Ager (2007).
%extern{
#include "net_util.h"
#include "Event.h"
extern RecordType* conn_id;
#include "events.bif.h"
%}
%include bro.pac
%include netflow-analyzer.pac
%include netflow-protocol.pac

View file

@ -6,5 +6,5 @@ bro_plugin_begin(Bro RDP)
bro_plugin_cc(RDP.cc Plugin.cc)
bro_plugin_bif(events.bif)
bro_plugin_bif(types.bif)
bro_plugin_pac(rdp.pac rdp-analyzer.pac rdp-protocol.pac)
bro_plugin_pac(rdp.pac rdp-analyzer.pac rdp-protocol.pac ../asn1/asn1.pac)
bro_plugin_end()

View file

@ -12,6 +12,13 @@ refine flow RDP_Flow += {
size_t widesize = utf16.length();
size_t utf8size = 3 * widesize + 1;
if ( utf8size > resultstring.max_size() )
{
connection()->bro_analyzer()->Weird("excessive_utf16_length");
return new StringVal("");
}
resultstring.resize(utf8size, '\0');
const UTF16* sourcestart = reinterpret_cast<const UTF16*>(utf16.begin());
const UTF16* sourceend = sourcestart + widesize;

View file

@ -1,3 +1,4 @@
%include ../asn1/asn1.pac
type TPKT(is_orig: bool) = record {
version: uint8;
@ -326,64 +327,6 @@ type X509_Cert_Data = record {
cert: bytestring &length=cert_len;
} &byteorder=littleendian;
######################################################################
# ASN.1 Encodings
######################################################################
type ASN1Encoding = record {
meta: ASN1EncodingMeta;
content: bytestring &length = meta.length;
};
type ASN1EncodingMeta = record {
tag: uint8;
len: uint8;
more_len: bytestring &length = long_len ? len & 0x7f : 0;
} &let {
long_len: bool = (len & 0x80) > 0;
length: uint64 = long_len ? binary_to_int64(more_len) : len & 0x7f;
};
type ASN1SequenceMeta = record {
encoding: ASN1EncodingMeta;
};
type ASN1Integer = record {
encoding: ASN1Encoding;
};
type ASN1OctetString = record {
encoding: ASN1Encoding;
};
type ASN1ObjectIdentifier = record {
encoding: ASN1Encoding;
};
type ASN1Boolean = record {
encoding: ASN1Encoding;
};
type ASN1Enumerated = record {
encoding: ASN1Encoding;
};
######################################################################
# ASN.1 Conversion Functions
######################################################################
function binary_to_int64(bs: bytestring): int64
%{
int64 rval = 0;
for ( int i = 0; i < bs.length(); ++i )
{
uint64 byte = bs[i];
rval |= byte << (8 * (bs.length() - (i + 1)));
}
return rval;
%}
refine connection RDP_Conn += {
%member{

View file

@ -0,0 +1,14 @@
include(BroPlugin)
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
bro_plugin_begin(Bro SIP)
bro_plugin_cc(Plugin.cc)
bro_plugin_cc(SIP.cc)
bro_plugin_cc(SIP_TCP.cc)
bro_plugin_bif(events.bif)
bro_plugin_pac(sip.pac sip-analyzer.pac sip-protocol.pac)
bro_plugin_pac(sip_TCP.pac sip-protocol.pac sip-analyzer.pac)
bro_plugin_end()

View file

@ -0,0 +1,29 @@
// See the file in the main distribution directory for copyright.
#include "plugin/Plugin.h"
#include "SIP.h"
#include "SIP_TCP.h"
namespace plugin {
namespace Bro_SIP {
class Plugin : public plugin::Plugin {
public:
plugin::Configuration Configure()
{
AddComponent(new ::analyzer::Component("SIP", ::analyzer::SIP::SIP_Analyzer::Instantiate));
// We don't fully support SIP-over-TCP yet, so we don't activate this component.
// AddComponent(new ::analyzer::Component("SIP_TCP", ::analyzer::sip_tcp::SIP_Analyzer::Instantiate));
plugin::Configuration config;
config.name = "Bro::SIP";
config.description = "SIP analyzer UDP-only";
return config;
}
} plugin;
}
}

Some files were not shown because too many files have changed in this diff Show more