mirror of
https://github.com/zeek/zeek.git
synced 2025-10-17 05:58:20 +00:00
Merge remote-tracking branch 'origin/master' into topic/dnthayer/doc-improvements-2.4
This commit is contained in:
commit
9cde2be727
653 changed files with 25848 additions and 7940 deletions
|
@ -53,7 +53,8 @@ function set_limit(f: fa_file, args: Files::AnalyzerArgs, n: count): bool
|
|||
function on_add(f: fa_file, args: Files::AnalyzerArgs)
|
||||
{
|
||||
if ( ! args?$extract_filename )
|
||||
args$extract_filename = cat("extract-", f$source, "-", f$id);
|
||||
args$extract_filename = cat("extract-", f$last_active, "-", f$source,
|
||||
"-", f$id);
|
||||
|
||||
f$info$extracted = args$extract_filename;
|
||||
args$extract_filename = build_path_compressed(prefix, args$extract_filename);
|
||||
|
|
2
scripts/base/files/pe/__load__.bro
Normal file
2
scripts/base/files/pe/__load__.bro
Normal file
|
@ -0,0 +1,2 @@
|
|||
@load ./consts
|
||||
@load ./main
|
184
scripts/base/files/pe/consts.bro
Normal file
184
scripts/base/files/pe/consts.bro
Normal 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); };
|
||||
|
||||
}
|
137
scripts/base/files/pe/main.bro
Normal file
137
scripts/base/files/pe/main.bro
Normal 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);
|
||||
}
|
||||
|
|
@ -195,7 +195,7 @@ event Input::end_of_data(name: string, source: string)
|
|||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(Unified2::LOG, [$columns=Info, $ev=log_unified2]);
|
||||
Log::create_stream(Unified2::LOG, [$columns=Info, $ev=log_unified2, $path="unified2"]);
|
||||
|
||||
if ( sid_msg == "" )
|
||||
{
|
||||
|
|
|
@ -36,7 +36,7 @@ export {
|
|||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(X509::LOG, [$columns=Info, $ev=log_x509]);
|
||||
Log::create_stream(X509::LOG, [$columns=Info, $ev=log_x509, $path="x509"]);
|
||||
}
|
||||
|
||||
redef record Files::Info += {
|
||||
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
1
scripts/base/frameworks/broker/__load__.bro
Normal file
1
scripts/base/frameworks/broker/__load__.bro
Normal file
|
@ -0,0 +1 @@
|
|||
@load ./main
|
103
scripts/base/frameworks/broker/main.bro
Normal file
103
scripts/base/frameworks/broker/main.bro
Normal file
|
@ -0,0 +1,103 @@
|
|||
##! Various data structure definitions for use with Bro's communication system.
|
||||
|
||||
module BrokerComm;
|
||||
|
||||
export {
|
||||
|
||||
## A name used to identify this endpoint to peers.
|
||||
## .. bro:see:: BrokerComm::connect BrokerComm::listen
|
||||
const endpoint_name = "" &redef;
|
||||
|
||||
## Change communication behavior.
|
||||
type EndpointFlags: record {
|
||||
## Whether to restrict message topics that can be published to peers.
|
||||
auto_publish: bool &default = T;
|
||||
## Whether to restrict what message topics or data store identifiers
|
||||
## the local endpoint advertises to peers (e.g. subscribing to
|
||||
## events or making a master data store available).
|
||||
auto_advertise: bool &default = T;
|
||||
};
|
||||
|
||||
## Fine-grained tuning of communication behavior for a particular message.
|
||||
type SendFlags: record {
|
||||
## Send the message to the local endpoint.
|
||||
self: bool &default = F;
|
||||
## Send the message to peer endpoints that advertise interest in
|
||||
## the topic associated with the message.
|
||||
peers: bool &default = T;
|
||||
## Send the message to peer endpoints even if they don't advertise
|
||||
## interest in the topic associated with the message.
|
||||
unsolicited: bool &default = F;
|
||||
};
|
||||
|
||||
## Opaque communication data.
|
||||
type Data: record {
|
||||
d: opaque of BrokerComm::Data &optional;
|
||||
};
|
||||
|
||||
## Opaque communication data.
|
||||
type DataVector: vector of BrokerComm::Data;
|
||||
|
||||
## Opaque event communication data.
|
||||
type EventArgs: record {
|
||||
## The name of the event. Not set if invalid event or arguments.
|
||||
name: string &optional;
|
||||
## The arguments to the event.
|
||||
args: DataVector;
|
||||
};
|
||||
|
||||
## Opaque communication data used as a convenient way to wrap key-value
|
||||
## pairs that comprise table entries.
|
||||
type TableItem : record {
|
||||
key: BrokerComm::Data;
|
||||
val: BrokerComm::Data;
|
||||
};
|
||||
}
|
||||
|
||||
module BrokerStore;
|
||||
|
||||
export {
|
||||
|
||||
## Whether a data store query could be completed or not.
|
||||
type QueryStatus: enum {
|
||||
SUCCESS,
|
||||
FAILURE,
|
||||
};
|
||||
|
||||
## An expiry time for a key-value pair inserted in to a data store.
|
||||
type ExpiryTime: record {
|
||||
## Absolute point in time at which to expire the entry.
|
||||
absolute: time &optional;
|
||||
## A point in time relative to the last modification time at which
|
||||
## to expire the entry. New modifications will delay the expiration.
|
||||
since_last_modification: interval &optional;
|
||||
};
|
||||
|
||||
## The result of a data store query.
|
||||
type QueryResult: record {
|
||||
## Whether the query completed or not.
|
||||
status: BrokerStore::QueryStatus;
|
||||
## The result of the query. Certain queries may use a particular
|
||||
## data type (e.g. querying store size always returns a count, but
|
||||
## a lookup may return various data types).
|
||||
result: BrokerComm::Data;
|
||||
};
|
||||
|
||||
## Options to tune the SQLite storage backend.
|
||||
type SQLiteOptions: record {
|
||||
## File system path of the database.
|
||||
path: string &default = "store.sqlite";
|
||||
};
|
||||
|
||||
## Options to tune the RocksDB storage backend.
|
||||
type RocksDBOptions: record {
|
||||
## File system path of the database.
|
||||
path: string &default = "store.rocksdb";
|
||||
};
|
||||
|
||||
## Options to tune the particular storage backends.
|
||||
type BackendOptions: record {
|
||||
sqlite: SQLiteOptions &default = SQLiteOptions();
|
||||
rocksdb: RocksDBOptions &default = RocksDBOptions();
|
||||
};
|
||||
}
|
|
@ -159,5 +159,5 @@ event bro_init() &priority=5
|
|||
terminate();
|
||||
}
|
||||
|
||||
Log::create_stream(Cluster::LOG, [$columns=Info]);
|
||||
Log::create_stream(Cluster::LOG, [$columns=Info, $path="cluster"]);
|
||||
}
|
||||
|
|
|
@ -164,7 +164,7 @@ const src_names = {
|
|||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(Communication::LOG, [$columns=Info]);
|
||||
Log::create_stream(Communication::LOG, [$columns=Info, $path="communication"]);
|
||||
}
|
||||
|
||||
function do_script_log_common(level: count, src: count, msg: string)
|
||||
|
|
|
@ -38,7 +38,7 @@ redef record connection += {
|
|||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(DPD::LOG, [$columns=Info]);
|
||||
Log::create_stream(DPD::LOG, [$columns=Info, $path="dpd"]);
|
||||
}
|
||||
|
||||
event protocol_confirmation(c: connection, atype: Analyzer::Tag, aid: count) &priority=10
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
@load-sigs ./archive
|
||||
@load-sigs ./audio
|
||||
@load-sigs ./font
|
||||
@load-sigs ./general
|
||||
@load-sigs ./image
|
||||
@load-sigs ./msoffice
|
||||
@load-sigs ./libmagic
|
||||
@load-sigs ./video
|
||||
|
||||
@load-sigs ./libmagic
|
176
scripts/base/frameworks/files/magic/archive.sig
Normal file
176
scripts/base/frameworks/files/magic/archive.sig
Normal 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/
|
||||
}
|
||||
|
13
scripts/base/frameworks/files/magic/audio.sig
Normal file
13
scripts/base/frameworks/files/magic/audio.sig
Normal 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)/
|
||||
}
|
||||
|
41
scripts/base/frameworks/files/magic/font.sig
Normal file
41
scripts/base/frameworks/files/magic/font.sig
Normal 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/
|
||||
}
|
|
@ -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)/
|
||||
}
|
||||
|
|
166
scripts/base/frameworks/files/magic/image.sig
Normal file
166
scripts/base/frameworks/files/magic/image.sig
Normal 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
|
@ -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/
|
||||
}
|
||||
|
||||
|
|
96
scripts/base/frameworks/files/magic/video.sig
Normal file
96
scripts/base/frameworks/files/magic/video.sig
Normal 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)/
|
||||
}
|
|
@ -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.
|
||||
|
@ -313,7 +312,7 @@ global analyzer_add_callbacks: table[Files::Tag] of function(f: fa_file, args: A
|
|||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(Files::LOG, [$columns=Info, $ev=log_files]);
|
||||
Log::create_stream(Files::LOG, [$columns=Info, $ev=log_files, $path="files"]);
|
||||
}
|
||||
|
||||
function set_info(f: fa_file)
|
||||
|
@ -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)];
|
||||
|
|
|
@ -32,6 +32,8 @@ export {
|
|||
FILE_NAME,
|
||||
## Certificate SHA-1 hash.
|
||||
CERT_HASH,
|
||||
## Public key MD5 hash. (SSH server host keys are a good example.)
|
||||
PUBKEY_HASH,
|
||||
};
|
||||
|
||||
## Data about an :bro:type:`Intel::Item`.
|
||||
|
@ -174,7 +176,7 @@ global min_data_store: MinDataStore &redef;
|
|||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(LOG, [$columns=Info, $ev=log_intel]);
|
||||
Log::create_stream(LOG, [$columns=Info, $ev=log_intel, $path="intel"]);
|
||||
}
|
||||
|
||||
function find(s: Seen): bool
|
||||
|
|
|
@ -50,11 +50,17 @@ export {
|
|||
## The event receives a single same parameter, an instance of
|
||||
## type ``columns``.
|
||||
ev: any &optional;
|
||||
|
||||
## A path that will be inherited by any filters added to the
|
||||
## stream which do not already specify their own path.
|
||||
path: string &optional;
|
||||
};
|
||||
|
||||
## Builds the default path values for log filters if not otherwise
|
||||
## specified by a filter. The default implementation uses *id*
|
||||
## to derive a name.
|
||||
## to derive a name. Upon adding a filter to a stream, if neither
|
||||
## ``path`` nor ``path_func`` is explicitly set by them, then
|
||||
## this function is used as the ``path_func``.
|
||||
##
|
||||
## id: The ID associated with the log stream.
|
||||
##
|
||||
|
@ -144,7 +150,9 @@ export {
|
|||
## to compute the string dynamically. It is ok to return
|
||||
## different strings for separate calls, but be careful: it's
|
||||
## easy to flood the disk by returning a new string for each
|
||||
## connection.
|
||||
## connection. Upon adding a filter to a stream, if neither
|
||||
## ``path`` nor ``path_func`` is explicitly set by them, then
|
||||
## :bro:see:`default_path_func` is used.
|
||||
##
|
||||
## id: The ID associated with the log stream.
|
||||
##
|
||||
|
@ -380,6 +388,8 @@ export {
|
|||
global active_streams: table[ID] of Stream = table();
|
||||
}
|
||||
|
||||
global all_streams: table[ID] of Stream = table();
|
||||
|
||||
# We keep a script-level copy of all filters so that we can manipulate them.
|
||||
global filters: table[ID, string] of Filter;
|
||||
|
||||
|
@ -464,6 +474,7 @@ function create_stream(id: ID, stream: Stream) : bool
|
|||
return F;
|
||||
|
||||
active_streams[id] = stream;
|
||||
all_streams[id] = stream;
|
||||
|
||||
return add_default_filter(id);
|
||||
}
|
||||
|
@ -471,6 +482,7 @@ function create_stream(id: ID, stream: Stream) : bool
|
|||
function remove_stream(id: ID) : bool
|
||||
{
|
||||
delete active_streams[id];
|
||||
delete all_streams[id];
|
||||
return __remove_stream(id);
|
||||
}
|
||||
|
||||
|
@ -483,10 +495,12 @@ function disable_stream(id: ID) : bool
|
|||
|
||||
function add_filter(id: ID, filter: Filter) : bool
|
||||
{
|
||||
# This is a work-around for the fact that we can't forward-declare
|
||||
# the default_path_func and then use it as &default in the record
|
||||
# definition.
|
||||
if ( ! filter?$path_func )
|
||||
local stream = all_streams[id];
|
||||
|
||||
if ( stream?$path && ! filter?$path )
|
||||
filter$path = stream$path;
|
||||
|
||||
if ( ! filter?$path && ! filter?$path_func )
|
||||
filter$path_func = default_path_func;
|
||||
|
||||
filters[id, filter$name] = filter;
|
||||
|
|
|
@ -37,6 +37,8 @@ export {
|
|||
user: string;
|
||||
## The remote host to which to transfer logs.
|
||||
host: string;
|
||||
## The port to connect to. Defaults to 22
|
||||
host_port: count &default=22;
|
||||
## The path/directory on the remote host to send logs.
|
||||
path: string;
|
||||
};
|
||||
|
@ -63,8 +65,8 @@ function sftp_postprocessor(info: Log::RotationInfo): bool
|
|||
{
|
||||
local dst = fmt("%s/%s.%s.log", d$path, info$path,
|
||||
strftime(Log::sftp_rotation_date_format, info$open));
|
||||
command += fmt("echo put %s %s | sftp -b - %s@%s;", info$fname, dst,
|
||||
d$user, d$host);
|
||||
command += fmt("echo put %s %s | sftp -P %d -b - %s@%s;", info$fname, dst,
|
||||
d$host_port, d$user, d$host);
|
||||
}
|
||||
|
||||
command += fmt("/bin/rm %s", info$fname);
|
||||
|
|
|
@ -19,9 +19,9 @@ export {
|
|||
## the :bro:id:`NOTICE` function. The convention is to give a general
|
||||
## category along with the specific notice separating words with
|
||||
## underscores and using leading capitals on each word except for
|
||||
## abbreviations which are kept in all capitals. For example,
|
||||
## abbreviations which are kept in all capitals. For example,
|
||||
## SSH::Password_Guessing is for hosts that have crossed a threshold of
|
||||
## heuristically determined failed SSH logins.
|
||||
## failed SSH logins.
|
||||
type Type: enum {
|
||||
## Notice reporting a count of how often a notice occurred.
|
||||
Tally,
|
||||
|
@ -349,9 +349,9 @@ function log_mailing_postprocessor(info: Log::RotationInfo): bool
|
|||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(Notice::LOG, [$columns=Info, $ev=log_notice]);
|
||||
Log::create_stream(Notice::LOG, [$columns=Info, $ev=log_notice, $path="notice"]);
|
||||
|
||||
Log::create_stream(Notice::ALARM_LOG, [$columns=Notice::Info]);
|
||||
Log::create_stream(Notice::ALARM_LOG, [$columns=Notice::Info, $path="notice_alarm"]);
|
||||
# If Bro is configured for mailing notices, set up mailing for alarms.
|
||||
# Make sure that this alarm log is also output as text so that it can
|
||||
# be packaged up and emailed later.
|
||||
|
|
|
@ -294,7 +294,7 @@ global current_conn: connection;
|
|||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(Weird::LOG, [$columns=Info, $ev=log_weird]);
|
||||
Log::create_stream(Weird::LOG, [$columns=Info, $ev=log_weird, $path="weird"]);
|
||||
}
|
||||
|
||||
function flow_id_string(src: addr, dst: addr): string
|
||||
|
|
|
@ -159,7 +159,7 @@ event filter_change_tracking()
|
|||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(PacketFilter::LOG, [$columns=Info]);
|
||||
Log::create_stream(PacketFilter::LOG, [$columns=Info, $path="packet_filter"]);
|
||||
|
||||
# Preverify the capture and restrict filters to give more granular failure messages.
|
||||
for ( id in capture_filters )
|
||||
|
|
|
@ -45,7 +45,7 @@ export {
|
|||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(Reporter::LOG, [$columns=Info]);
|
||||
Log::create_stream(Reporter::LOG, [$columns=Info, $path="reporter"]);
|
||||
}
|
||||
|
||||
event reporter_info(t: time, msg: string, location: string) &priority=-5
|
||||
|
|
|
@ -142,7 +142,7 @@ global did_sig_log: set[string] &read_expire = 1 hr;
|
|||
|
||||
event bro_init()
|
||||
{
|
||||
Log::create_stream(Signatures::LOG, [$columns=Info, $ev=log_signature]);
|
||||
Log::create_stream(Signatures::LOG, [$columns=Info, $ev=log_signature, $path="signatures"]);
|
||||
}
|
||||
|
||||
# Returns true if the given signature has already been triggered for the given
|
||||
|
@ -277,7 +277,7 @@ event signature_match(state: signature_state, msg: string, data: string)
|
|||
orig, sig_id, hcount);
|
||||
|
||||
Log::write(Signatures::LOG,
|
||||
[$note=Multiple_Sig_Responders,
|
||||
[$ts=network_time(), $note=Multiple_Sig_Responders,
|
||||
$src_addr=orig, $sig_id=sig_id, $event_msg=msg,
|
||||
$host_count=hcount, $sub_msg=horz_scan_msg]);
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ export {
|
|||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(Software::LOG, [$columns=Info, $ev=log_software]);
|
||||
Log::create_stream(Software::LOG, [$columns=Info, $ev=log_software, $path="software"]);
|
||||
}
|
||||
|
||||
type Description: record {
|
||||
|
|
|
@ -89,7 +89,7 @@ redef likely_server_ports += { ayiya_ports, teredo_ports, gtpv1_ports };
|
|||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(Tunnel::LOG, [$columns=Info]);
|
||||
Log::create_stream(Tunnel::LOG, [$columns=Info, $path="tunnel"]);
|
||||
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_AYIYA, ayiya_ports);
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_TEREDO, teredo_ports);
|
||||
|
|
|
@ -333,8 +333,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.
|
||||
|
@ -414,6 +412,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
|
||||
|
@ -440,6 +446,7 @@ type NetStats: record {
|
|||
## packet capture system, this value may not be available and will then
|
||||
## be always set to zero.
|
||||
pkts_link: count &default=0;
|
||||
bytes_recvd: count &default=0; ##< Bytes received by Bro.
|
||||
};
|
||||
|
||||
## Statistics about Bro's resource consumption.
|
||||
|
@ -928,7 +935,7 @@ const tcp_storm_interarrival_thresh = 1 sec &redef;
|
|||
## seeing our peer's ACKs. Set to zero to turn off this determination.
|
||||
##
|
||||
## .. bro:see:: tcp_max_above_hole_without_any_acks tcp_excessive_data_without_further_acks
|
||||
const tcp_max_initial_window = 4096 &redef;
|
||||
const tcp_max_initial_window = 16384 &redef;
|
||||
|
||||
## If we're not seeing our peer's ACKs, the maximum volume of data above a
|
||||
## sequence hole that we'll tolerate before assuming that there's been a packet
|
||||
|
@ -936,7 +943,7 @@ const tcp_max_initial_window = 4096 &redef;
|
|||
## don't ever give up.
|
||||
##
|
||||
## .. bro:see:: tcp_max_initial_window tcp_excessive_data_without_further_acks
|
||||
const tcp_max_above_hole_without_any_acks = 4096 &redef;
|
||||
const tcp_max_above_hole_without_any_acks = 16384 &redef;
|
||||
|
||||
## If we've seen this much data without any of it being acked, we give up
|
||||
## on that connection to avoid memory exhaustion due to buffering all that
|
||||
|
@ -1080,27 +1087,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.
|
||||
|
@ -2215,6 +2201,41 @@ export {
|
|||
const heartbeat_interval = 1.0 secs &redef;
|
||||
}
|
||||
|
||||
module SSH;
|
||||
|
||||
export {
|
||||
## The client and server each have some preferences for the algorithms used
|
||||
## in each direction.
|
||||
type Algorithm_Prefs: record {
|
||||
## The algorithm preferences for client to server communication
|
||||
client_to_server: vector of string &optional;
|
||||
## The algorithm preferences for server to client communication
|
||||
server_to_client: vector of string &optional;
|
||||
};
|
||||
|
||||
## This record lists the preferences of an SSH endpoint for
|
||||
## algorithm selection. During the initial :abbr:`SSH (Secure Shell)`
|
||||
## key exchange, each endpoint lists the algorithms
|
||||
## that it supports, in order of preference. See
|
||||
## :rfc:`4253#section-7.1` for details.
|
||||
type Capabilities: record {
|
||||
## Key exchange algorithms
|
||||
kex_algorithms: string_vec;
|
||||
## The algorithms supported for the server host key
|
||||
server_host_key_algorithms: string_vec;
|
||||
## Symmetric encryption algorithm preferences
|
||||
encryption_algorithms: Algorithm_Prefs;
|
||||
## Symmetric MAC algorithm preferences
|
||||
mac_algorithms: Algorithm_Prefs;
|
||||
## Compression algorithm preferences
|
||||
compression_algorithms: Algorithm_Prefs;
|
||||
## Language preferences
|
||||
languages: Algorithm_Prefs &optional;
|
||||
## Are these the capabilities of the server?
|
||||
is_server: bool;
|
||||
};
|
||||
}
|
||||
|
||||
module GLOBAL;
|
||||
|
||||
## An NTP message.
|
||||
|
@ -2511,6 +2532,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
|
||||
|
@ -2635,60 +2795,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
|
||||
|
@ -2774,19 +2880,20 @@ export {
|
|||
module X509;
|
||||
export {
|
||||
type Certificate: record {
|
||||
version: count; ##< Version number.
|
||||
serial: string; ##< Serial number.
|
||||
subject: string; ##< Subject.
|
||||
issuer: string; ##< Issuer.
|
||||
not_valid_before: time; ##< Timestamp before when certificate is not valid.
|
||||
not_valid_after: time; ##< Timestamp after when certificate is not valid.
|
||||
key_alg: string; ##< Name of the key algorithm
|
||||
sig_alg: string; ##< Name of the signature algorithm
|
||||
key_type: string &optional; ##< Key type, if key parseable by openssl (either rsa, dsa or ec)
|
||||
key_length: count &optional; ##< Key length in bits
|
||||
exponent: string &optional; ##< Exponent, if RSA-certificate
|
||||
curve: string &optional; ##< Curve, if EC-certificate
|
||||
} &log;
|
||||
version: count &log; ##< Version number.
|
||||
serial: string &log; ##< Serial number.
|
||||
subject: string &log; ##< Subject.
|
||||
issuer: string &log; ##< Issuer.
|
||||
cn: string &optional; ##< Last (most specific) common name.
|
||||
not_valid_before: time &log; ##< Timestamp before when certificate is not valid.
|
||||
not_valid_after: time &log; ##< Timestamp after when certificate is not valid.
|
||||
key_alg: string &log; ##< Name of the key algorithm
|
||||
sig_alg: string &log; ##< Name of the signature algorithm
|
||||
key_type: string &optional &log; ##< Key type, if key parseable by openssl (either rsa, dsa or ec)
|
||||
key_length: count &optional &log; ##< Key length in bits
|
||||
exponent: string &optional &log; ##< Exponent, if RSA-certificate
|
||||
curve: string &optional &log; ##< Curve, if EC-certificate
|
||||
};
|
||||
|
||||
type Extension: record {
|
||||
name: string; ##< Long name of extension. oid if name not known
|
||||
|
@ -2847,7 +2954,44 @@ export {
|
|||
attributes : RADIUS::Attributes &optional;
|
||||
};
|
||||
}
|
||||
module GLOBAL;
|
||||
|
||||
module RDP;
|
||||
export {
|
||||
type RDP::EarlyCapabilityFlags: record {
|
||||
support_err_info_pdu: bool;
|
||||
want_32bpp_session: bool;
|
||||
support_statusinfo_pdu: bool;
|
||||
strong_asymmetric_keys: bool;
|
||||
support_monitor_layout_pdu: bool;
|
||||
support_netchar_autodetect: bool;
|
||||
support_dynvc_gfx_protocol: bool;
|
||||
support_dynamic_time_zone: bool;
|
||||
support_heartbeat_pdu: bool;
|
||||
};
|
||||
|
||||
type RDP::ClientCoreData: record {
|
||||
version_major: count;
|
||||
version_minor: count;
|
||||
desktop_width: count;
|
||||
desktop_height: count;
|
||||
color_depth: count;
|
||||
sas_sequence: count;
|
||||
keyboard_layout: count;
|
||||
client_build: count;
|
||||
client_name: string;
|
||||
keyboard_type: count;
|
||||
keyboard_sub: count;
|
||||
keyboard_function_key: count;
|
||||
ime_file_name: string;
|
||||
post_beta2_color_depth: count &optional;
|
||||
client_product_id: string &optional;
|
||||
serial_number: count &optional;
|
||||
high_color_depth: count &optional;
|
||||
supported_color_depths: count &optional;
|
||||
ec_flags: RDP::EarlyCapabilityFlags &optional;
|
||||
dig_product_id: string &optional;
|
||||
};
|
||||
}
|
||||
|
||||
@load base/bif/plugins/Bro_SNMP.types.bif
|
||||
|
||||
|
@ -2971,6 +3115,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
|
||||
|
@ -3133,6 +3457,11 @@ const forward_remote_events = F &redef;
|
|||
## more sophisticated script-level communication framework.
|
||||
const forward_remote_state_changes = F &redef;
|
||||
|
||||
## The number of IO chunks allowed to be buffered between the child
|
||||
## and parent process of remote communication before Bro starts dropping
|
||||
## connections to remote peers in an attempt to catch up.
|
||||
const chunked_io_buffer_soft_cap = 800000 &redef;
|
||||
|
||||
## Place-holder constant indicating "no peer".
|
||||
const PEER_ID_NONE = 0;
|
||||
|
||||
|
@ -3358,6 +3687,7 @@ const bits_per_uid: count = 96 &redef;
|
|||
|
||||
# Load these frameworks here because they use fairly deep integration with
|
||||
# BiFs and script-land defined types.
|
||||
@load base/frameworks/broker
|
||||
@load base/frameworks/logging
|
||||
@load base/frameworks/input
|
||||
@load base/frameworks/analyzer
|
||||
|
|
|
@ -45,10 +45,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
|
||||
|
@ -57,6 +60,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
|
||||
|
|
|
@ -50,7 +50,7 @@ event ChecksumOffloading::check()
|
|||
bad_checksum_msg += "UDP";
|
||||
}
|
||||
|
||||
local message = fmt("Your %s invalid %s checksums, most likely from NIC checksum offloading.", packet_src, bad_checksum_msg);
|
||||
local message = fmt("Your %s invalid %s checksums, most likely from NIC checksum offloading. By default, packets with invalid checksums are discarded by Bro unless using the -C command-line option or toggling the 'ignore_checksums' variable. Alternatively, disable checksum offloading by the network adapter to ensure Bro analyzes the actual checksums that are transmitted.", packet_src, bad_checksum_msg);
|
||||
Reporter::warning(message);
|
||||
done = T;
|
||||
}
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
@load ./contents
|
||||
@load ./inactivity
|
||||
@load ./polling
|
||||
@load ./thresholds
|
||||
|
|
|
@ -127,7 +127,7 @@ redef record connection += {
|
|||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(Conn::LOG, [$columns=Info, $ev=log_conn]);
|
||||
Log::create_stream(Conn::LOG, [$columns=Info, $ev=log_conn, $path="conn"]);
|
||||
}
|
||||
|
||||
function conn_state(c: connection, trans: transport_proto): string
|
||||
|
|
256
scripts/base/protocols/conn/thresholds.bro
Normal file
256
scripts/base/protocols/conn/thresholds.bro
Normal file
|
@ -0,0 +1,256 @@
|
|||
##! Implements a generic API to throw events when a connection crosses a
|
||||
##! fixed threshold of bytes or packets.
|
||||
|
||||
module ConnThreshold;
|
||||
|
||||
export {
|
||||
|
||||
type Thresholds: record {
|
||||
orig_byte: set[count] &default=count_set(); ##< current originator byte thresholds we watch for
|
||||
resp_byte: set[count] &default=count_set(); ##< current responder byte thresholds we watch for
|
||||
orig_packet: set[count] &default=count_set(); ##< corrent originator packet thresholds we watch for
|
||||
resp_packet: set[count] &default=count_set(); ##< corrent responder packet thresholds we watch for
|
||||
};
|
||||
|
||||
## Sets a byte threshold for connection sizes, adding it to potentially already existing thresholds.
|
||||
## conn_bytes_threshold_crossed will be raised for each set threshold.
|
||||
##
|
||||
## cid: The connection id.
|
||||
##
|
||||
## threshold: Threshold in bytes.
|
||||
##
|
||||
## is_orig: If true, threshold is set for bytes from originator, otherwise for bytes from responder.
|
||||
##
|
||||
## Returns: T on success, F on failure.
|
||||
global set_bytes_threshold: function(c: connection, threshold: count, is_orig: bool): bool;
|
||||
|
||||
## Sets a packet threshold for connection sizes, adding it to potentially already existing thresholds.
|
||||
## conn_packets_threshold_crossed will be raised for each set threshold.
|
||||
##
|
||||
## cid: The connection id.
|
||||
##
|
||||
## threshold: Threshold in packets.
|
||||
##
|
||||
## is_orig: If true, threshold is set for packets from originator, otherwise for packets from responder.
|
||||
##
|
||||
## Returns: T on success, F on failure.
|
||||
global set_packets_threshold: function(c: connection, threshold: count, is_orig: bool): bool;
|
||||
|
||||
## Deletes a byte threshold for connection sizes.
|
||||
##
|
||||
## cid: The connection id.
|
||||
##
|
||||
## threshold: Threshold in bytes to remove.
|
||||
##
|
||||
## is_orig: If true, threshold is removed for packets from originator, otherwhise for packets from responder.
|
||||
##
|
||||
## Returns: T on success, F on failure.
|
||||
global delete_bytes_threshold: function(c: connection, threshold: count, is_orig: bool): bool;
|
||||
|
||||
## Deletes a packet threshold for connection sizes.
|
||||
##
|
||||
## cid: The connection id.
|
||||
##
|
||||
## threshold: Threshold in packets.
|
||||
##
|
||||
## is_orig: If true, threshold is removed for packets from originator, otherwise for packets from responder.
|
||||
##
|
||||
## Returns: T on success, F on failure.
|
||||
global delete_packets_threshold: function(c: connection, threshold: count, is_orig: bool): bool;
|
||||
|
||||
## Generated for a connection that crossed a set byte threshold
|
||||
##
|
||||
## c: the connection
|
||||
##
|
||||
## threshold: the threshold that was set
|
||||
##
|
||||
## is_orig: True if the threshold was crossed by the originator of the connection
|
||||
global bytes_threshold_crossed: event(c: connection, threshold: count, is_orig: bool);
|
||||
|
||||
## Generated for a connection that crossed a set byte threshold
|
||||
##
|
||||
## c: the connection
|
||||
##
|
||||
## threshold: the threshold that was set
|
||||
##
|
||||
## is_orig: True if the threshold was crossed by the originator of the connection
|
||||
global packets_threshold_crossed: event(c: connection, threshold: count, is_orig: bool);
|
||||
}
|
||||
|
||||
redef record connection += {
|
||||
thresholds: ConnThreshold::Thresholds &optional;
|
||||
};
|
||||
|
||||
function set_conn(c: connection)
|
||||
{
|
||||
if ( c?$thresholds )
|
||||
return;
|
||||
|
||||
c$thresholds = Thresholds();
|
||||
}
|
||||
|
||||
function find_min_threshold(t: set[count]): count
|
||||
{
|
||||
if ( |t| == 0 )
|
||||
return 0;
|
||||
|
||||
local first = T;
|
||||
local min: count = 0;
|
||||
|
||||
for ( i in t )
|
||||
{
|
||||
if ( first )
|
||||
{
|
||||
min = i;
|
||||
first = F;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( i < min )
|
||||
min = i;
|
||||
}
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
function set_current_threshold(c: connection, bytes: bool, is_orig: bool): bool
|
||||
{
|
||||
local t: count = 0;
|
||||
local cur: count = 0;
|
||||
|
||||
if ( bytes && is_orig )
|
||||
{
|
||||
t = find_min_threshold(c$thresholds$orig_byte);
|
||||
cur = get_current_conn_bytes_threshold(c$id, is_orig);
|
||||
}
|
||||
else if ( bytes && ! is_orig )
|
||||
{
|
||||
t = find_min_threshold(c$thresholds$resp_byte);
|
||||
cur = get_current_conn_bytes_threshold(c$id, is_orig);
|
||||
}
|
||||
else if ( ! bytes && is_orig )
|
||||
{
|
||||
t = find_min_threshold(c$thresholds$orig_packet);
|
||||
cur = get_current_conn_packets_threshold(c$id, is_orig);
|
||||
}
|
||||
else if ( ! bytes && ! is_orig )
|
||||
{
|
||||
t = find_min_threshold(c$thresholds$resp_packet);
|
||||
cur = get_current_conn_packets_threshold(c$id, is_orig);
|
||||
}
|
||||
|
||||
if ( t == cur )
|
||||
return T;
|
||||
|
||||
if ( bytes && is_orig )
|
||||
return set_current_conn_bytes_threshold(c$id, t, T);
|
||||
else if ( bytes && ! is_orig )
|
||||
return set_current_conn_bytes_threshold(c$id, t, F);
|
||||
else if ( ! bytes && is_orig )
|
||||
return set_current_conn_packets_threshold(c$id, t, T);
|
||||
else if ( ! bytes && ! is_orig )
|
||||
return set_current_conn_packets_threshold(c$id, t, F);
|
||||
}
|
||||
|
||||
function set_bytes_threshold(c: connection, threshold: count, is_orig: bool): bool
|
||||
{
|
||||
set_conn(c);
|
||||
|
||||
if ( threshold == 0 )
|
||||
return F;
|
||||
|
||||
if ( is_orig )
|
||||
add c$thresholds$orig_byte[threshold];
|
||||
else
|
||||
add c$thresholds$resp_byte[threshold];
|
||||
|
||||
return set_current_threshold(c, T, is_orig);
|
||||
}
|
||||
|
||||
function set_packets_threshold(c: connection, threshold: count, is_orig: bool): bool
|
||||
{
|
||||
set_conn(c);
|
||||
|
||||
if ( threshold == 0 )
|
||||
return F;
|
||||
|
||||
if ( is_orig )
|
||||
add c$thresholds$orig_packet[threshold];
|
||||
else
|
||||
add c$thresholds$resp_packet[threshold];
|
||||
|
||||
return set_current_threshold(c, F, is_orig);
|
||||
}
|
||||
|
||||
function delete_bytes_threshold(c: connection, threshold: count, is_orig: bool): bool
|
||||
{
|
||||
set_conn(c);
|
||||
|
||||
if ( is_orig && threshold in c$thresholds$orig_byte )
|
||||
{
|
||||
delete c$thresholds$orig_byte[threshold];
|
||||
set_current_threshold(c, T, is_orig);
|
||||
return T;
|
||||
}
|
||||
else if ( ! is_orig && threshold in c$thresholds$resp_byte )
|
||||
{
|
||||
delete c$thresholds$resp_byte[threshold];
|
||||
set_current_threshold(c, T, is_orig);
|
||||
return T;
|
||||
}
|
||||
|
||||
return F;
|
||||
}
|
||||
|
||||
function delete_packets_threshold(c: connection, threshold: count, is_orig: bool): bool
|
||||
{
|
||||
set_conn(c);
|
||||
|
||||
if ( is_orig && threshold in c$thresholds$orig_packet )
|
||||
{
|
||||
delete c$thresholds$orig_packet[threshold];
|
||||
set_current_threshold(c, F, is_orig);
|
||||
return T;
|
||||
}
|
||||
else if ( ! is_orig && threshold in c$thresholds$resp_packet )
|
||||
{
|
||||
delete c$thresholds$resp_packet[threshold];
|
||||
set_current_threshold(c, F, is_orig);
|
||||
return T;
|
||||
}
|
||||
|
||||
return F;
|
||||
}
|
||||
|
||||
event conn_bytes_threshold_crossed(c: connection, threshold: count, is_orig: bool) &priority=5
|
||||
{
|
||||
if ( is_orig && threshold in c$thresholds$orig_byte )
|
||||
{
|
||||
delete c$thresholds$orig_byte[threshold];
|
||||
event ConnThreshold::bytes_threshold_crossed(c, threshold, is_orig);
|
||||
}
|
||||
else if ( ! is_orig && threshold in c$thresholds$resp_byte )
|
||||
{
|
||||
delete c$thresholds$resp_byte[threshold];
|
||||
event ConnThreshold::bytes_threshold_crossed(c, threshold, is_orig);
|
||||
}
|
||||
|
||||
set_current_threshold(c, T, is_orig);
|
||||
}
|
||||
|
||||
event conn_packets_threshold_crossed(c: connection, threshold: count, is_orig: bool) &priority=5
|
||||
{
|
||||
if ( is_orig && threshold in c$thresholds$orig_packet )
|
||||
{
|
||||
delete c$thresholds$orig_packet[threshold];
|
||||
event ConnThreshold::packets_threshold_crossed(c, threshold, is_orig);
|
||||
}
|
||||
else if ( ! is_orig && threshold in c$thresholds$resp_packet )
|
||||
{
|
||||
delete c$thresholds$resp_packet[threshold];
|
||||
event ConnThreshold::packets_threshold_crossed(c, threshold, is_orig);
|
||||
}
|
||||
|
||||
set_current_threshold(c, F, is_orig);
|
||||
}
|
|
@ -49,7 +49,7 @@ redef likely_server_ports += { 67/udp };
|
|||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(DHCP::LOG, [$columns=Info, $ev=log_dhcp]);
|
||||
Log::create_stream(DHCP::LOG, [$columns=Info, $ev=log_dhcp, $path="dhcp"]);
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_DHCP, ports);
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ redef likely_server_ports += { ports };
|
|||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(DNP3::LOG, [$columns=Info, $ev=log_dnp3]);
|
||||
Log::create_stream(DNP3::LOG, [$columns=Info, $ev=log_dnp3, $path="dnp3"]);
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_DNP3_TCP, ports);
|
||||
}
|
||||
|
||||
|
|
|
@ -150,7 +150,7 @@ redef likely_server_ports += { ports };
|
|||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(DNS::LOG, [$columns=Info, $ev=log_dns]);
|
||||
Log::create_stream(DNS::LOG, [$columns=Info, $ev=log_dns, $path="dns"]);
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_DNS, ports);
|
||||
}
|
||||
|
||||
|
@ -305,6 +305,9 @@ hook DNS::do_reply(c: connection, msg: dns_msg, ans: dns_answer, reply: string)
|
|||
|
||||
if ( ans$answer_type == DNS_ANS )
|
||||
{
|
||||
if ( ! c$dns?$query )
|
||||
c$dns$query = ans$query;
|
||||
|
||||
c$dns$AA = msg$AA;
|
||||
c$dns$RA = msg$RA;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -11,13 +11,13 @@
|
|||
##! GridFTP data channels are identified by a heuristic that relies on
|
||||
##! the fact that default settings for GridFTP clients typically
|
||||
##! mutually authenticate the data channel with TLS/SSL and negotiate a
|
||||
##! NULL bulk cipher (no encryption). Connections with those
|
||||
##! attributes are then polled for two minutes with decreasing frequency
|
||||
##! to check if the transfer sizes are large enough to indicate a
|
||||
##! GridFTP data channel that would be undesirable to analyze further
|
||||
##! (e.g. stop TCP reassembly). A side effect is that true connection
|
||||
##! sizes are not logged, but at the benefit of saving CPU cycles that
|
||||
##! would otherwise go to analyzing the large (and likely benign) connections.
|
||||
##! NULL bulk cipher (no encryption). Connections with those attributes
|
||||
##! are marked as GridFTP if the data transfer within the first two minutes
|
||||
##! is big enough to indicate a GripFTP data channel that would be
|
||||
##! undesirable to analyze further (e.g. stop TCP reassembly). A side
|
||||
##! effect is that true connection sizes are not logged, but at the benefit
|
||||
##! of saving CPU cycles that would otherwise go to analyzing the large
|
||||
##! (and likely benign) connections.
|
||||
|
||||
@load ./info
|
||||
@load ./main
|
||||
|
@ -32,23 +32,14 @@ export {
|
|||
## GridFTP data channel.
|
||||
const size_threshold = 1073741824 &redef;
|
||||
|
||||
## Max number of times to check whether a connection's size exceeds the
|
||||
## Time during which we check whether a connection's size exceeds the
|
||||
## :bro:see:`GridFTP::size_threshold`.
|
||||
const max_poll_count = 15 &redef;
|
||||
const max_time = 2 min &redef;
|
||||
|
||||
## Whether to skip further processing of the GridFTP data channel once
|
||||
## detected, which may help performance.
|
||||
const skip_data = T &redef;
|
||||
|
||||
## Base amount of time between checking whether a GridFTP data connection
|
||||
## has transferred more than :bro:see:`GridFTP::size_threshold` bytes.
|
||||
const poll_interval = 1sec &redef;
|
||||
|
||||
## The amount of time the base :bro:see:`GridFTP::poll_interval` is
|
||||
## increased by each poll interval. Can be used to make more frequent
|
||||
## checks at the start of a connection and gradually slow down.
|
||||
const poll_interval_increase = 1sec &redef;
|
||||
|
||||
## Raised when a GridFTP data channel is detected.
|
||||
##
|
||||
## c: The connection pertaining to the GridFTP data channel.
|
||||
|
@ -79,23 +70,27 @@ event ftp_request(c: connection, command: string, arg: string) &priority=4
|
|||
c$ftp$last_auth_requested = arg;
|
||||
}
|
||||
|
||||
function size_callback(c: connection, cnt: count): interval
|
||||
event ConnThreshold::bytes_threshold_crossed(c: connection, threshold: count, is_orig: bool)
|
||||
{
|
||||
if ( c$orig$size > size_threshold || c$resp$size > size_threshold )
|
||||
if ( threshold < size_threshold || "gridftp-data" in c$service || c$duration > max_time )
|
||||
return;
|
||||
|
||||
add c$service["gridftp-data"];
|
||||
event GridFTP::data_channel_detected(c);
|
||||
|
||||
if ( skip_data )
|
||||
skip_further_processing(c$id);
|
||||
}
|
||||
|
||||
event gridftp_possibility_timeout(c: connection)
|
||||
{
|
||||
# only remove if we did not already detect it and the connection
|
||||
# is not yet at its end.
|
||||
if ( "gridftp-data" !in c$service && ! c$conn?$service )
|
||||
{
|
||||
add c$service["gridftp-data"];
|
||||
event GridFTP::data_channel_detected(c);
|
||||
|
||||
if ( skip_data )
|
||||
skip_further_processing(c$id);
|
||||
|
||||
return -1sec;
|
||||
ConnThreshold::delete_bytes_threshold(c, size_threshold, T);
|
||||
ConnThreshold::delete_bytes_threshold(c, size_threshold, F);
|
||||
}
|
||||
|
||||
if ( cnt >= max_poll_count )
|
||||
return -1sec;
|
||||
|
||||
return poll_interval + poll_interval_increase * cnt;
|
||||
}
|
||||
|
||||
event ssl_established(c: connection) &priority=5
|
||||
|
@ -118,5 +113,9 @@ event ssl_established(c: connection) &priority=-3
|
|||
# By default GridFTP data channels do mutual authentication and
|
||||
# negotiate a cipher suite with a NULL bulk cipher.
|
||||
if ( data_channel_initial_criteria(c) )
|
||||
ConnPolling::watch(c, size_callback, 0, 0secs);
|
||||
{
|
||||
ConnThreshold::set_bytes_threshold(c, size_threshold, T);
|
||||
ConnThreshold::set_bytes_threshold(c, size_threshold, F);
|
||||
schedule max_time { gridftp_possibility_timeout(c) };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ redef likely_server_ports += { ports };
|
|||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(FTP::LOG, [$columns=Info, $ev=log_ftp]);
|
||||
Log::create_stream(FTP::LOG, [$columns=Info, $ev=log_ftp, $path="ftp"]);
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_FTP, ports);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
@ -135,7 +139,7 @@ redef likely_server_ports += { ports };
|
|||
# Initialize the HTTP logging stream and ports.
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(HTTP::LOG, [$columns=Info, $ev=log_http]);
|
||||
Log::create_stream(HTTP::LOG, [$columns=Info, $ev=log_http, $path="http"]);
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_HTTP, ports);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ redef likely_server_ports += { ports };
|
|||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(IRC::LOG, [$columns=Info, $ev=irc_log]);
|
||||
Log::create_stream(IRC::LOG, [$columns=Info, $ev=irc_log, $path="irc"]);
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_IRC, ports);
|
||||
}
|
||||
|
||||
|
|
3
scripts/base/protocols/krb/__load__.bro
Normal file
3
scripts/base/protocols/krb/__load__.bro
Normal file
|
@ -0,0 +1,3 @@
|
|||
@load ./main
|
||||
@load ./files
|
||||
@load-sigs ./dpd.sig
|
99
scripts/base/protocols/krb/consts.bro
Normal file
99
scripts/base/protocols/krb/consts.bro
Normal 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",
|
||||
};
|
||||
|
||||
}
|
26
scripts/base/protocols/krb/dpd.sig
Normal file
26
scripts/base/protocols/krb/dpd.sig
Normal 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"
|
||||
}
|
||||
|
142
scripts/base/protocols/krb/files.bro
Normal file
142
scripts/base/protocols/krb/files.bro
Normal 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);
|
||||
}
|
250
scripts/base/protocols/krb/main.bro
Normal file
250
scripts/base/protocols/krb/main.bro
Normal 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);
|
||||
}
|
|
@ -34,7 +34,7 @@ redef likely_server_ports += { ports };
|
|||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(Modbus::LOG, [$columns=Info, $ev=log_modbus]);
|
||||
Log::create_stream(Modbus::LOG, [$columns=Info, $ev=log_modbus, $path="modbus"]);
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_MODBUS, ports);
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ const ports = { 1434/tcp, 3306/tcp };
|
|||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(mysql::LOG, [$columns=Info, $ev=log_mysql]);
|
||||
Log::create_stream(mysql::LOG, [$columns=Info, $ev=log_mysql, $path="mysql"]);
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_MYSQL, ports);
|
||||
}
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ const ports = { 1812/udp };
|
|||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(RADIUS::LOG, [$columns=Info, $ev=log_radius]);
|
||||
Log::create_stream(RADIUS::LOG, [$columns=Info, $ev=log_radius, $path="radius"]);
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_RADIUS, ports);
|
||||
}
|
||||
|
||||
|
|
3
scripts/base/protocols/rdp/__load__.bro
Normal file
3
scripts/base/protocols/rdp/__load__.bro
Normal file
|
@ -0,0 +1,3 @@
|
|||
@load ./consts
|
||||
@load ./main
|
||||
@load-sigs ./dpd.sig
|
323
scripts/base/protocols/rdp/consts.bro
Normal file
323
scripts/base/protocols/rdp/consts.bro
Normal file
|
@ -0,0 +1,323 @@
|
|||
module RDP;
|
||||
|
||||
export {
|
||||
# http://www.c-amie.co.uk/technical/mstsc-versions/
|
||||
const builds = {
|
||||
[0419] = "RDP 4.0",
|
||||
[2195] = "RDP 5.0",
|
||||
[2221] = "RDP 5.0",
|
||||
[2600] = "RDP 5.1",
|
||||
[3790] = "RDP 5.2",
|
||||
[6000] = "RDP 6.0",
|
||||
[6001] = "RDP 6.1",
|
||||
[6002] = "RDP 6.2",
|
||||
[7600] = "RDP 7.0",
|
||||
[7601] = "RDP 7.1",
|
||||
[9200] = "RDP 8.0",
|
||||
[9600] = "RDP 8.1",
|
||||
[25189] = "RDP 8.0 (Mac)",
|
||||
[25282] = "RDP 8.0 (Mac)"
|
||||
} &default = function(n: count): string { return fmt("client_build-%d", n); };
|
||||
|
||||
const security_protocols = {
|
||||
[0x00] = "RDP",
|
||||
[0x01] = "SSL",
|
||||
[0x02] = "HYBRID",
|
||||
[0x08] = "HYBRID_EX"
|
||||
} &default = function(n: count): string { return fmt("security_protocol-%d", n); };
|
||||
|
||||
const failure_codes = {
|
||||
[0x01] = "SSL_REQUIRED_BY_SERVER",
|
||||
[0x02] = "SSL_NOT_ALLOWED_BY_SERVER",
|
||||
[0x03] = "SSL_CERT_NOT_ON_SERVER",
|
||||
[0x04] = "INCONSISTENT_FLAGS",
|
||||
[0x05] = "HYBRID_REQUIRED_BY_SERVER",
|
||||
[0x06] = "SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER"
|
||||
} &default = function(n: count): string { return fmt("failure_code-%d", n); };
|
||||
|
||||
const cert_types = {
|
||||
[1] = "RSA",
|
||||
[2] = "X.509"
|
||||
} &default = function(n: count): string { return fmt("cert_type-%d", n); };
|
||||
|
||||
const encryption_methods = {
|
||||
[0] = "None",
|
||||
[1] = "40bit",
|
||||
[2] = "128bit",
|
||||
[8] = "56bit",
|
||||
[10] = "FIPS"
|
||||
} &default = function(n: count): string { return fmt("encryption_method-%d", n); };
|
||||
|
||||
const encryption_levels = {
|
||||
[0] = "None",
|
||||
[1] = "Low",
|
||||
[2] = "Client compatible",
|
||||
[3] = "High",
|
||||
[4] = "FIPS"
|
||||
} &default = function(n: count): string { return fmt("encryption_level-%d", n); };
|
||||
|
||||
const high_color_depths = {
|
||||
[0x0004] = "4bit",
|
||||
[0x0008] = "8bit",
|
||||
[0x000F] = "15bit",
|
||||
[0x0010] = "16bit",
|
||||
[0x0018] = "24bit"
|
||||
} &default = function(n: count): string { return fmt("high_color_depth-%d", n); };
|
||||
|
||||
const color_depths = {
|
||||
[0x0001] = "24bit",
|
||||
[0x0002] = "16bit",
|
||||
[0x0004] = "15bit",
|
||||
[0x0008] = "32bit"
|
||||
} &default = function(n: count): string { return fmt("color_depth-%d", n); };
|
||||
|
||||
const results = {
|
||||
[0] = "Success",
|
||||
[1] = "User rejected",
|
||||
[2] = "Resources not available",
|
||||
[3] = "Rejected for symmetry breaking",
|
||||
[4] = "Locked conference",
|
||||
} &default = function(n: count): string { return fmt("result-%d", n); };
|
||||
|
||||
# http://msdn.microsoft.com/en-us/goglobal/bb964664.aspx
|
||||
const languages = {
|
||||
[1078] = "Afrikaans - South Africa",
|
||||
[1052] = "Albanian - Albania",
|
||||
[1156] = "Alsatian",
|
||||
[1118] = "Amharic - Ethiopia",
|
||||
[1025] = "Arabic - Saudi Arabia",
|
||||
[5121] = "Arabic - Algeria",
|
||||
[15361] = "Arabic - Bahrain",
|
||||
[3073] = "Arabic - Egypt",
|
||||
[2049] = "Arabic - Iraq",
|
||||
[11265] = "Arabic - Jordan",
|
||||
[13313] = "Arabic - Kuwait",
|
||||
[12289] = "Arabic - Lebanon",
|
||||
[4097] = "Arabic - Libya",
|
||||
[6145] = "Arabic - Morocco",
|
||||
[8193] = "Arabic - Oman",
|
||||
[16385] = "Arabic - Qatar",
|
||||
[10241] = "Arabic - Syria",
|
||||
[7169] = "Arabic - Tunisia",
|
||||
[14337] = "Arabic - U.A.E.",
|
||||
[9217] = "Arabic - Yemen",
|
||||
[1067] = "Armenian - Armenia",
|
||||
[1101] = "Assamese",
|
||||
[2092] = "Azeri (Cyrillic)",
|
||||
[1068] = "Azeri (Latin)",
|
||||
[1133] = "Bashkir",
|
||||
[1069] = "Basque",
|
||||
[1059] = "Belarusian",
|
||||
[1093] = "Bengali (India)",
|
||||
[2117] = "Bengali (Bangladesh)",
|
||||
[5146] = "Bosnian (Bosnia/Herzegovina)",
|
||||
[1150] = "Breton",
|
||||
[1026] = "Bulgarian",
|
||||
[1109] = "Burmese",
|
||||
[1027] = "Catalan",
|
||||
[1116] = "Cherokee - United States",
|
||||
[2052] = "Chinese - People's Republic of China",
|
||||
[4100] = "Chinese - Singapore",
|
||||
[1028] = "Chinese - Taiwan",
|
||||
[3076] = "Chinese - Hong Kong SAR",
|
||||
[5124] = "Chinese - Macao SAR",
|
||||
[1155] = "Corsican",
|
||||
[1050] = "Croatian",
|
||||
[4122] = "Croatian (Bosnia/Herzegovina)",
|
||||
[1029] = "Czech",
|
||||
[1030] = "Danish",
|
||||
[1164] = "Dari",
|
||||
[1125] = "Divehi",
|
||||
[1043] = "Dutch - Netherlands",
|
||||
[2067] = "Dutch - Belgium",
|
||||
[1126] = "Edo",
|
||||
[1033] = "English - United States",
|
||||
[2057] = "English - United Kingdom",
|
||||
[3081] = "English - Australia",
|
||||
[10249] = "English - Belize",
|
||||
[4105] = "English - Canada",
|
||||
[9225] = "English - Caribbean",
|
||||
[15369] = "English - Hong Kong SAR",
|
||||
[16393] = "English - India",
|
||||
[14345] = "English - Indonesia",
|
||||
[6153] = "English - Ireland",
|
||||
[8201] = "English - Jamaica",
|
||||
[17417] = "English - Malaysia",
|
||||
[5129] = "English - New Zealand",
|
||||
[13321] = "English - Philippines",
|
||||
[18441] = "English - Singapore",
|
||||
[7177] = "English - South Africa",
|
||||
[11273] = "English - Trinidad",
|
||||
[12297] = "English - Zimbabwe",
|
||||
[1061] = "Estonian",
|
||||
[1080] = "Faroese",
|
||||
[1065] = "Farsi",
|
||||
[1124] = "Filipino",
|
||||
[1035] = "Finnish",
|
||||
[1036] = "French - France",
|
||||
[2060] = "French - Belgium",
|
||||
[11276] = "French - Cameroon",
|
||||
[3084] = "French - Canada",
|
||||
[9228] = "French - Democratic Rep. of Congo",
|
||||
[12300] = "French - Cote d'Ivoire",
|
||||
[15372] = "French - Haiti",
|
||||
[5132] = "French - Luxembourg",
|
||||
[13324] = "French - Mali",
|
||||
[6156] = "French - Monaco",
|
||||
[14348] = "French - Morocco",
|
||||
[58380] = "French - North Africa",
|
||||
[8204] = "French - Reunion",
|
||||
[10252] = "French - Senegal",
|
||||
[4108] = "French - Switzerland",
|
||||
[7180] = "French - West Indies",
|
||||
[1122] = "French - West Indies",
|
||||
[1127] = "Fulfulde - Nigeria",
|
||||
[1071] = "FYRO Macedonian",
|
||||
[1110] = "Galician",
|
||||
[1079] = "Georgian",
|
||||
[1031] = "German - Germany",
|
||||
[3079] = "German - Austria",
|
||||
[5127] = "German - Liechtenstein",
|
||||
[4103] = "German - Luxembourg",
|
||||
[2055] = "German - Switzerland",
|
||||
[1032] = "Greek",
|
||||
[1135] = "Greenlandic",
|
||||
[1140] = "Guarani - Paraguay",
|
||||
[1095] = "Gujarati",
|
||||
[1128] = "Hausa - Nigeria",
|
||||
[1141] = "Hawaiian - United States",
|
||||
[1037] = "Hebrew",
|
||||
[1081] = "Hindi",
|
||||
[1038] = "Hungarian",
|
||||
[1129] = "Ibibio - Nigeria",
|
||||
[1039] = "Icelandic",
|
||||
[1136] = "Igbo - Nigeria",
|
||||
[1057] = "Indonesian",
|
||||
[1117] = "Inuktitut",
|
||||
[2108] = "Irish",
|
||||
[1040] = "Italian - Italy",
|
||||
[2064] = "Italian - Switzerland",
|
||||
[1041] = "Japanese",
|
||||
[1158] = "K'iche",
|
||||
[1099] = "Kannada",
|
||||
[1137] = "Kanuri - Nigeria",
|
||||
[2144] = "Kashmiri",
|
||||
[1120] = "Kashmiri (Arabic)",
|
||||
[1087] = "Kazakh",
|
||||
[1107] = "Khmer",
|
||||
[1159] = "Kinyarwanda",
|
||||
[1111] = "Konkani",
|
||||
[1042] = "Korean",
|
||||
[1088] = "Kyrgyz (Cyrillic)",
|
||||
[1108] = "Lao",
|
||||
[1142] = "Latin",
|
||||
[1062] = "Latvian",
|
||||
[1063] = "Lithuanian",
|
||||
[1134] = "Luxembourgish",
|
||||
[1086] = "Malay - Malaysia",
|
||||
[2110] = "Malay - Brunei Darussalam",
|
||||
[1100] = "Malayalam",
|
||||
[1082] = "Maltese",
|
||||
[1112] = "Manipuri",
|
||||
[1153] = "Maori - New Zealand",
|
||||
[1146] = "Mapudungun",
|
||||
[1102] = "Marathi",
|
||||
[1148] = "Mohawk",
|
||||
[1104] = "Mongolian (Cyrillic)",
|
||||
[2128] = "Mongolian (Mongolian)",
|
||||
[1121] = "Nepali",
|
||||
[2145] = "Nepali - India",
|
||||
[1044] = "Norwegian (Bokmål)",
|
||||
[2068] = "Norwegian (Nynorsk)",
|
||||
[1154] = "Occitan",
|
||||
[1096] = "Oriya",
|
||||
[1138] = "Oromo",
|
||||
[1145] = "Papiamentu",
|
||||
[1123] = "Pashto",
|
||||
[1045] = "Polish",
|
||||
[1046] = "Portuguese - Brazil",
|
||||
[2070] = "Portuguese - Portugal",
|
||||
[1094] = "Punjabi",
|
||||
[2118] = "Punjabi (Pakistan)",
|
||||
[1131] = "Quecha - Bolivia",
|
||||
[2155] = "Quecha - Ecuador",
|
||||
[3179] = "Quecha - Peru CB",
|
||||
[1047] = "Rhaeto-Romanic",
|
||||
[1048] = "Romanian",
|
||||
[2072] = "Romanian - Moldava",
|
||||
[1049] = "Russian",
|
||||
[2073] = "Russian - Moldava",
|
||||
[1083] = "Sami (Lappish)",
|
||||
[1103] = "Sanskrit",
|
||||
[1084] = "Scottish Gaelic",
|
||||
[1132] = "Sepedi",
|
||||
[3098] = "Serbian (Cyrillic)",
|
||||
[2074] = "Serbian (Latin)",
|
||||
[1113] = "Sindhi - India",
|
||||
[2137] = "Sindhi - Pakistan",
|
||||
[1115] = "Sinhalese - Sri Lanka",
|
||||
[1051] = "Slovak",
|
||||
[1060] = "Slovenian",
|
||||
[1143] = "Somali",
|
||||
[1070] = "Sorbian",
|
||||
[3082] = "Spanish - Spain (Modern Sort)",
|
||||
[1034] = "Spanish - Spain (Traditional Sort)",
|
||||
[11274] = "Spanish - Argentina",
|
||||
[16394] = "Spanish - Bolivia",
|
||||
[13322] = "Spanish - Chile",
|
||||
[9226] = "Spanish - Colombia",
|
||||
[5130] = "Spanish - Costa Rica",
|
||||
[7178] = "Spanish - Dominican Republic",
|
||||
[12298] = "Spanish - Ecuador",
|
||||
[17418] = "Spanish - El Salvador",
|
||||
[4106] = "Spanish - Guatemala",
|
||||
[18442] = "Spanish - Honduras",
|
||||
[22538] = "Spanish - Latin America",
|
||||
[2058] = "Spanish - Mexico",
|
||||
[19466] = "Spanish - Nicaragua",
|
||||
[6154] = "Spanish - Panama",
|
||||
[15370] = "Spanish - Paraguay",
|
||||
[10250] = "Spanish - Peru",
|
||||
[20490] = "Spanish - Puerto Rico",
|
||||
[21514] = "Spanish - United States",
|
||||
[14346] = "Spanish - Uruguay",
|
||||
[8202] = "Spanish - Venezuela",
|
||||
[1072] = "Sutu",
|
||||
[1089] = "Swahili",
|
||||
[1053] = "Swedish",
|
||||
[2077] = "Swedish - Finland",
|
||||
[1114] = "Syriac",
|
||||
[1064] = "Tajik",
|
||||
[1119] = "Tamazight (Arabic)",
|
||||
[2143] = "Tamazight (Latin)",
|
||||
[1097] = "Tamil",
|
||||
[1092] = "Tatar",
|
||||
[1098] = "Telugu",
|
||||
[1054] = "Thai",
|
||||
[2129] = "Tibetan - Bhutan",
|
||||
[1105] = "Tibetan - People's Republic of China",
|
||||
[2163] = "Tigrigna - Eritrea",
|
||||
[1139] = "Tigrigna - Ethiopia",
|
||||
[1073] = "Tsonga",
|
||||
[1074] = "Tswana",
|
||||
[1055] = "Turkish",
|
||||
[1090] = "Turkmen",
|
||||
[1152] = "Uighur - China",
|
||||
[1058] = "Ukrainian",
|
||||
[1056] = "Urdu",
|
||||
[2080] = "Urdu - India",
|
||||
[2115] = "Uzbek (Cyrillic)",
|
||||
[1091] = "Uzbek (Latin)",
|
||||
[1075] = "Venda",
|
||||
[1066] = "Vietnamese",
|
||||
[1106] = "Welsh",
|
||||
[1160] = "Wolof",
|
||||
[1076] = "Xhosa",
|
||||
[1157] = "Yakut",
|
||||
[1144] = "Yi",
|
||||
[1085] = "Yiddish",
|
||||
[1130] = "Yoruba",
|
||||
[1077] = "Zulu",
|
||||
[1279] = "HID (Human Interface Device)",
|
||||
} &default = function(n: count): string { return fmt("keyboard-%d", n); };
|
||||
}
|
12
scripts/base/protocols/rdp/dpd.sig
Normal file
12
scripts/base/protocols/rdp/dpd.sig
Normal file
|
@ -0,0 +1,12 @@
|
|||
signature dpd_rdp_client {
|
||||
ip-proto == tcp
|
||||
# Client request
|
||||
payload /.*(Cookie: mstshash\=|Duca.*(rdpdr|rdpsnd|drdynvc|cliprdr))/
|
||||
requires-reverse-signature dpd_rdp_server
|
||||
enable "rdp"
|
||||
}
|
||||
|
||||
signature dpd_rdp_server {
|
||||
ip-proto == tcp
|
||||
payload /(.{5}\xd0|.*McDn)/
|
||||
}
|
269
scripts/base/protocols/rdp/main.bro
Normal file
269
scripts/base/protocols/rdp/main.bro
Normal file
|
@ -0,0 +1,269 @@
|
|||
##! Implements base functionality for RDP analysis. Generates the rdp.log file.
|
||||
|
||||
@load ./consts
|
||||
|
||||
module RDP;
|
||||
|
||||
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;
|
||||
## Cookie value used by the client machine.
|
||||
## This is typically a username.
|
||||
cookie: string &log &optional;
|
||||
## Status result for the connection. It's a mix between
|
||||
## RDP negotation failure messages and GCC server create
|
||||
## response messages.
|
||||
result: string &log &optional;
|
||||
## Security protocol chosen by the server.
|
||||
security_protocol: string &log &optional;
|
||||
|
||||
## Keyboard layout (language) of the client machine.
|
||||
keyboard_layout: string &log &optional;
|
||||
## RDP client version used by the client machine.
|
||||
client_build: string &log &optional;
|
||||
## Name of the client machine.
|
||||
client_name: string &log &optional;
|
||||
## Product ID of the client machine.
|
||||
client_dig_product_id: string &log &optional;
|
||||
## Desktop width of the client machine.
|
||||
desktop_width: count &log &optional;
|
||||
## Desktop height of the client machine.
|
||||
desktop_height: count &log &optional;
|
||||
## The color depth requested by the client in
|
||||
## the high_color_depth field.
|
||||
requested_color_depth: string &log &optional;
|
||||
|
||||
## If the connection is being encrypted with native
|
||||
## RDP encryption, this is the type of cert
|
||||
## being used.
|
||||
cert_type: string &log &optional;
|
||||
## The number of certs seen. X.509 can transfer an
|
||||
## entire certificate chain.
|
||||
cert_count: count &log &default=0;
|
||||
## Indicates if the provided certificate or certificate
|
||||
## chain is permanent or temporary.
|
||||
cert_permanent: bool &log &optional;
|
||||
## Encryption level of the connection.
|
||||
encryption_level: string &log &optional;
|
||||
## Encryption method of the connection.
|
||||
encryption_method: string &log &optional;
|
||||
};
|
||||
|
||||
## If true, detach the RDP analyzer from the connection to prevent
|
||||
## continuing to process encrypted traffic.
|
||||
const disable_analyzer_after_detection = F &redef;
|
||||
|
||||
## The amount of time to monitor an RDP session from when it is first
|
||||
## identified. When this interval is reached, the session is logged.
|
||||
const rdp_check_interval = 10secs &redef;
|
||||
|
||||
## Event that can be handled to access the rdp record as it is sent on
|
||||
## to the logging framework.
|
||||
global log_rdp: event(rec: Info);
|
||||
}
|
||||
|
||||
# Internal fields that aren't useful externally
|
||||
redef record Info += {
|
||||
## The analyzer ID used for the analyzer instance attached
|
||||
## to each connection. It is not used for logging since it's a
|
||||
## meaningless arbitrary number.
|
||||
analyzer_id: count &optional;
|
||||
## Track status of logging RDP connections.
|
||||
done: bool &default=F;
|
||||
};
|
||||
|
||||
redef record connection += {
|
||||
rdp: Info &optional;
|
||||
};
|
||||
|
||||
const ports = { 3389/tcp };
|
||||
redef likely_server_ports += { ports };
|
||||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(RDP::LOG, [$columns=RDP::Info, $ev=log_rdp, $path="rdp"]);
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_RDP, ports);
|
||||
}
|
||||
|
||||
function write_log(c: connection)
|
||||
{
|
||||
local info = c$rdp;
|
||||
|
||||
if ( info$done )
|
||||
return;
|
||||
|
||||
# Mark this record as fully logged and finished.
|
||||
info$done = T;
|
||||
|
||||
# Verify that the RDP session contains
|
||||
# RDP data before writing it to the log.
|
||||
if ( info?$cookie || info?$keyboard_layout || info?$result )
|
||||
Log::write(RDP::LOG, info);
|
||||
}
|
||||
|
||||
event check_record(c: connection)
|
||||
{
|
||||
# If the record was logged, then stop processing.
|
||||
if ( c$rdp$done )
|
||||
return;
|
||||
|
||||
# If the value rdp_check_interval has passed since the
|
||||
# RDP session was started, then log the record.
|
||||
local diff = network_time() - c$rdp$ts;
|
||||
if ( diff > rdp_check_interval )
|
||||
{
|
||||
write_log(c);
|
||||
|
||||
# Remove the analyzer if it is still attached.
|
||||
if ( disable_analyzer_after_detection &&
|
||||
connection_exists(c$id) &&
|
||||
c$rdp?$analyzer_id )
|
||||
{
|
||||
disable_analyzer(c$id, c$rdp$analyzer_id);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
# If the analyzer is attached and the duration
|
||||
# to monitor the RDP session was not met, then
|
||||
# reschedule the logging event.
|
||||
schedule rdp_check_interval { check_record(c) };
|
||||
}
|
||||
}
|
||||
|
||||
function set_session(c: connection)
|
||||
{
|
||||
if ( ! c?$rdp )
|
||||
{
|
||||
c$rdp = [$ts=network_time(),$id=c$id,$uid=c$uid];
|
||||
# The RDP session is scheduled to be logged from
|
||||
# the time it is first initiated.
|
||||
schedule rdp_check_interval { check_record(c) };
|
||||
}
|
||||
}
|
||||
|
||||
event rdp_connect_request(c: connection, cookie: string) &priority=5
|
||||
{
|
||||
set_session(c);
|
||||
|
||||
c$rdp$cookie = cookie;
|
||||
}
|
||||
|
||||
event rdp_negotiation_response(c: connection, security_protocol: count) &priority=5
|
||||
{
|
||||
set_session(c);
|
||||
|
||||
c$rdp$security_protocol = security_protocols[security_protocol];
|
||||
}
|
||||
|
||||
event rdp_negotiation_failure(c: connection, failure_code: count) &priority=5
|
||||
{
|
||||
set_session(c);
|
||||
|
||||
c$rdp$result = failure_codes[failure_code];
|
||||
}
|
||||
|
||||
event rdp_client_core_data(c: connection, data: RDP::ClientCoreData) &priority=5
|
||||
{
|
||||
set_session(c);
|
||||
|
||||
c$rdp$keyboard_layout = RDP::languages[data$keyboard_layout];
|
||||
c$rdp$client_build = RDP::builds[data$client_build];
|
||||
c$rdp$client_name = data$client_name;
|
||||
c$rdp$client_dig_product_id = data$dig_product_id;
|
||||
c$rdp$desktop_width = data$desktop_width;
|
||||
c$rdp$desktop_height = data$desktop_height;
|
||||
|
||||
if ( data?$ec_flags && data$ec_flags$want_32bpp_session )
|
||||
c$rdp$requested_color_depth = "32bit";
|
||||
else
|
||||
c$rdp$requested_color_depth = RDP::high_color_depths[data$high_color_depth];
|
||||
}
|
||||
|
||||
event rdp_gcc_server_create_response(c: connection, result: count) &priority=5
|
||||
{
|
||||
set_session(c);
|
||||
|
||||
c$rdp$result = RDP::results[result];
|
||||
}
|
||||
|
||||
event rdp_server_security(c: connection, encryption_method: count, encryption_level: count) &priority=5
|
||||
{
|
||||
set_session(c);
|
||||
|
||||
c$rdp$encryption_method = RDP::encryption_methods[encryption_method];
|
||||
c$rdp$encryption_level = RDP::encryption_levels[encryption_level];
|
||||
}
|
||||
|
||||
event rdp_server_certificate(c: connection, cert_type: count, permanently_issued: bool) &priority=5
|
||||
{
|
||||
set_session(c);
|
||||
|
||||
c$rdp$cert_type = RDP::cert_types[cert_type];
|
||||
|
||||
# There are no events for proprietary/RSA certs right
|
||||
# now so we manually count this one.
|
||||
if ( c$rdp$cert_type == "RSA" )
|
||||
++c$rdp$cert_count;
|
||||
|
||||
c$rdp$cert_permanent = permanently_issued;
|
||||
}
|
||||
|
||||
event rdp_begin_encryption(c: connection, security_protocol: count) &priority=5
|
||||
{
|
||||
set_session(c);
|
||||
|
||||
if ( ! c$rdp?$result )
|
||||
{
|
||||
c$rdp$result = "encrypted";
|
||||
}
|
||||
|
||||
c$rdp$security_protocol = security_protocols[security_protocol];
|
||||
}
|
||||
|
||||
event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priority=5
|
||||
{
|
||||
if ( c?$rdp && f$source == "RDP" )
|
||||
{
|
||||
# Count up X509 certs.
|
||||
++c$rdp$cert_count;
|
||||
|
||||
Files::add_analyzer(f, Files::ANALYZER_X509);
|
||||
Files::add_analyzer(f, Files::ANALYZER_MD5);
|
||||
Files::add_analyzer(f, Files::ANALYZER_SHA1);
|
||||
}
|
||||
}
|
||||
|
||||
event protocol_confirmation(c: connection, atype: Analyzer::Tag, aid: count) &priority=5
|
||||
{
|
||||
if ( atype == Analyzer::ANALYZER_RDP )
|
||||
{
|
||||
set_session(c);
|
||||
c$rdp$analyzer_id = aid;
|
||||
}
|
||||
}
|
||||
|
||||
event protocol_violation(c: connection, atype: Analyzer::Tag, aid: count, reason: string) &priority=5
|
||||
{
|
||||
# If a protocol violation occurs, then log the record immediately.
|
||||
if ( c?$rdp )
|
||||
write_log(c);
|
||||
}
|
||||
|
||||
event connection_state_remove(c: connection) &priority=-5
|
||||
{
|
||||
# If the connection is removed, then log the record immediately.
|
||||
if ( c?$rdp )
|
||||
{
|
||||
write_log(c);
|
||||
}
|
||||
}
|
3
scripts/base/protocols/sip/__load__.bro
Normal file
3
scripts/base/protocols/sip/__load__.bro
Normal file
|
@ -0,0 +1,3 @@
|
|||
@load ./main
|
||||
|
||||
@load-sigs ./dpd.sig
|
19
scripts/base/protocols/sip/dpd.sig
Normal file
19
scripts/base/protocols/sip/dpd.sig
Normal 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"
|
||||
# }
|
272
scripts/base/protocols/sip/main.bro
Normal file
272
scripts/base/protocols/sip/main.bro
Normal 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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -92,7 +92,7 @@ redef likely_server_ports += { ports };
|
|||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(SMTP::LOG, [$columns=SMTP::Info, $ev=log_smtp]);
|
||||
Log::create_stream(SMTP::LOG, [$columns=SMTP::Info, $ev=log_smtp, $path="smtp"]);
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_SMTP, ports);
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ redef likely_server_ports += { ports };
|
|||
event bro_init() &priority=5
|
||||
{
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_SNMP, ports);
|
||||
Log::create_stream(SNMP::LOG, [$columns=SNMP::Info, $ev=log_snmp]);
|
||||
Log::create_stream(SNMP::LOG, [$columns=SNMP::Info, $ev=log_snmp, $path="snmp"]);
|
||||
}
|
||||
|
||||
function init_state(c: connection, h: SNMP::Header): Info
|
||||
|
|
|
@ -43,7 +43,7 @@ redef likely_server_ports += { ports };
|
|||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(SOCKS::LOG, [$columns=Info, $ev=log_socks]);
|
||||
Log::create_stream(SOCKS::LOG, [$columns=Info, $ev=log_socks, $path="socks"]);
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_SOCKS, ports);
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Support for Secure Shell (SSH) protocol analysis.
|
|
@ -1,3 +1,2 @@
|
|||
@load ./main
|
||||
|
||||
@load-sigs ./dpd.sig
|
||||
@load-sigs ./dpd.sig
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
signature dpd_ssh_client {
|
||||
ip-proto == tcp
|
||||
payload /^[sS][sS][hH]-/
|
||||
payload /^[sS][sS][hH]-[12]\./
|
||||
requires-reverse-signature dpd_ssh_server
|
||||
enable "ssh"
|
||||
tcp-state originator
|
||||
|
@ -8,6 +8,6 @@ signature dpd_ssh_client {
|
|||
|
||||
signature dpd_ssh_server {
|
||||
ip-proto == tcp
|
||||
payload /^[sS][sS][hH]-/
|
||||
payload /^[sS][sS][hH]-[12]\./
|
||||
tcp-state responder
|
||||
}
|
||||
}
|
|
@ -1,15 +1,5 @@
|
|||
##! Base SSH analysis script. The heuristic to blindly determine success or
|
||||
##! failure for SSH connections is implemented here. At this time, it only
|
||||
##! uses the size of the data being returned from the server to make the
|
||||
##! heuristic determination about success of the connection.
|
||||
##! Requires that :bro:id:`use_conn_size_analyzer` is set to T! The heuristic
|
||||
##! is not attempted if the connection size analyzer isn't enabled.
|
||||
##! Implements base functionality for SSH analysis. Generates the ssh.log file.
|
||||
|
||||
@load base/protocols/conn
|
||||
@load base/frameworks/notice
|
||||
@load base/utils/site
|
||||
@load base/utils/thresholds
|
||||
@load base/utils/conn-ids
|
||||
@load base/utils/directions-and-hosts
|
||||
|
||||
module SSH;
|
||||
|
@ -25,45 +15,63 @@ export {
|
|||
uid: string &log;
|
||||
## The connection's 4-tuple of endpoint addresses/ports.
|
||||
id: conn_id &log;
|
||||
## Indicates if the login was heuristically guessed to be
|
||||
## "success", "failure", or "undetermined".
|
||||
status: string &log &default="undetermined";
|
||||
## Direction of the connection. If the client was a local host
|
||||
## SSH major version (1 or 2)
|
||||
version: count &log;
|
||||
## Authentication result (T=success, F=failure, unset=unknown)
|
||||
auth_success: bool &log &optional;
|
||||
## Direction of the connection. If the client was a local host
|
||||
## logging into an external host, this would be OUTBOUND. INBOUND
|
||||
## would be set for the opposite situation.
|
||||
# TODO: handle local-local and remote-remote better.
|
||||
# TODO - handle local-local and remote-remote better.
|
||||
direction: Direction &log &optional;
|
||||
## Software string from the client.
|
||||
## The client's version string
|
||||
client: string &log &optional;
|
||||
## Software string from the server.
|
||||
## The server's version string
|
||||
server: string &log &optional;
|
||||
## Indicate if the SSH session is done being watched.
|
||||
done: bool &default=F;
|
||||
## The encryption algorithm in use
|
||||
cipher_alg: string &log &optional;
|
||||
## The signing (MAC) algorithm in use
|
||||
mac_alg: string &log &optional;
|
||||
## The compression algorithm in use
|
||||
compression_alg: string &log &optional;
|
||||
## The key exchange algorithm in use
|
||||
kex_alg: string &log &optional;
|
||||
## The server host key's algorithm
|
||||
host_key_alg: string &log &optional;
|
||||
## The server's key fingerprint
|
||||
host_key: string &log &optional;
|
||||
};
|
||||
|
||||
## The size in bytes of data sent by the server at which the SSH
|
||||
## connection is presumed to be successful.
|
||||
const authentication_data_size = 4000 &redef;
|
||||
## The set of compression algorithms. We can't accurately determine
|
||||
## authentication success or failure when compression is enabled.
|
||||
const compression_algorithms = set("zlib", "zlib@openssh.com") &redef;
|
||||
|
||||
## If true, we tell the event engine to not look at further data
|
||||
## packets after the initial SSH handshake. Helps with performance
|
||||
## (especially with large file transfers) but precludes some
|
||||
## kinds of analyses.
|
||||
const skip_processing_after_detection = F &redef;
|
||||
## kinds of analyses. Defaults to T.
|
||||
const skip_processing_after_detection = T &redef;
|
||||
|
||||
## Event that is generated when the heuristic thinks that a login
|
||||
## was successful.
|
||||
global heuristic_successful_login: event(c: connection);
|
||||
|
||||
## Event that is generated when the heuristic thinks that a login
|
||||
## failed.
|
||||
global heuristic_failed_login: event(c: connection);
|
||||
|
||||
## Event that can be handled to access the :bro:type:`SSH::Info`
|
||||
## record as it is sent on to the logging framework.
|
||||
## Event that can be handled to access the SSH record as it is sent on
|
||||
## to the logging framework.
|
||||
global log_ssh: event(rec: Info);
|
||||
|
||||
## Event that can be handled when the analyzer sees an SSH server host
|
||||
## key. This abstracts :bro:id:`ssh1_server_host_key` and
|
||||
## :bro:id:`ssh2_server_host_key`.
|
||||
global ssh_server_host_key: event(c: connection, hash: string);
|
||||
}
|
||||
|
||||
redef record Info += {
|
||||
# This connection has been logged (internal use)
|
||||
logged: bool &default=F;
|
||||
# Number of failures seen (internal use)
|
||||
num_failures: count &default=0;
|
||||
# Store capabilities from the first host for
|
||||
# comparison with the second (internal use)
|
||||
capabilities: Capabilities &optional;
|
||||
};
|
||||
|
||||
redef record connection += {
|
||||
ssh: Info &optional;
|
||||
};
|
||||
|
@ -72,133 +80,156 @@ const ports = { 22/tcp };
|
|||
redef likely_server_ports += { ports };
|
||||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(SSH::LOG, [$columns=Info, $ev=log_ssh]);
|
||||
{
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_SSH, ports);
|
||||
}
|
||||
Log::create_stream(SSH::LOG, [$columns=Info, $ev=log_ssh, $path="ssh"]);
|
||||
}
|
||||
|
||||
function set_session(c: connection)
|
||||
{
|
||||
if ( ! c?$ssh )
|
||||
{
|
||||
local info: Info;
|
||||
info$ts=network_time();
|
||||
info$uid=c$uid;
|
||||
info$id=c$id;
|
||||
local info: SSH::Info;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
function check_ssh_connection(c: connection, done: bool)
|
||||
{
|
||||
# If already done watching this connection, just return.
|
||||
if ( c$ssh$done )
|
||||
return;
|
||||
|
||||
if ( done )
|
||||
{
|
||||
# If this connection is done, then we can look to see if
|
||||
# this matches the conditions for a failed login. Failed
|
||||
# logins are only detected at connection state removal.
|
||||
|
||||
if ( # Require originators and responders to have sent at least 50 bytes.
|
||||
c$orig$size > 50 && c$resp$size > 50 &&
|
||||
# Responders must be below 4000 bytes.
|
||||
c$resp$size < authentication_data_size &&
|
||||
# Responder must have sent fewer than 40 packets.
|
||||
c$resp$num_pkts < 40 &&
|
||||
# If there was a content gap we can't reliably do this heuristic.
|
||||
c?$conn && c$conn$missed_bytes == 0 )# &&
|
||||
# Only "normal" connections can count.
|
||||
#c$conn?$conn_state && c$conn$conn_state in valid_states )
|
||||
{
|
||||
c$ssh$status = "failure";
|
||||
event SSH::heuristic_failed_login(c);
|
||||
}
|
||||
|
||||
if ( c$resp$size >= authentication_data_size )
|
||||
{
|
||||
c$ssh$status = "success";
|
||||
event SSH::heuristic_successful_login(c);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
# If this connection is still being tracked, then it's possible
|
||||
# to watch for it to be a successful connection.
|
||||
if ( c$resp$size >= authentication_data_size )
|
||||
{
|
||||
c$ssh$status = "success";
|
||||
event SSH::heuristic_successful_login(c);
|
||||
}
|
||||
else
|
||||
# This connection must be tracked longer. Let the scheduled
|
||||
# check happen again.
|
||||
return;
|
||||
}
|
||||
|
||||
# Set the direction for the log.
|
||||
c$ssh$direction = Site::is_local_addr(c$id$orig_h) ? OUTBOUND : INBOUND;
|
||||
|
||||
# Set the "done" flag to prevent the watching event from rescheduling
|
||||
# after detection is done.
|
||||
c$ssh$done=T;
|
||||
|
||||
if ( skip_processing_after_detection )
|
||||
{
|
||||
# Stop watching this connection, we don't care about it anymore.
|
||||
skip_further_processing(c$id);
|
||||
set_record_packets(c$id, F);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
event heuristic_successful_login(c: connection) &priority=-5
|
||||
{
|
||||
Log::write(SSH::LOG, c$ssh);
|
||||
}
|
||||
|
||||
event heuristic_failed_login(c: connection) &priority=-5
|
||||
{
|
||||
Log::write(SSH::LOG, c$ssh);
|
||||
}
|
||||
|
||||
event connection_state_remove(c: connection) &priority=-5
|
||||
{
|
||||
if ( c?$ssh )
|
||||
{
|
||||
check_ssh_connection(c, T);
|
||||
if ( c$ssh$status == "undetermined" )
|
||||
Log::write(SSH::LOG, c$ssh);
|
||||
}
|
||||
}
|
||||
|
||||
event ssh_watcher(c: connection)
|
||||
{
|
||||
local id = c$id;
|
||||
# don't go any further if this connection is gone already!
|
||||
if ( ! connection_exists(id) )
|
||||
return;
|
||||
|
||||
lookup_connection(c$id);
|
||||
check_ssh_connection(c, F);
|
||||
if ( ! c$ssh$done )
|
||||
schedule +15secs { ssh_watcher(c) };
|
||||
}
|
||||
|
||||
event ssh_server_version(c: connection, version: string) &priority=5
|
||||
event ssh_server_version(c: connection, version: string)
|
||||
{
|
||||
set_session(c);
|
||||
c$ssh$server = version;
|
||||
}
|
||||
|
||||
event ssh_client_version(c: connection, version: string) &priority=5
|
||||
event ssh_client_version(c: connection, version: string)
|
||||
{
|
||||
set_session(c);
|
||||
c$ssh$client = version;
|
||||
|
||||
# The heuristic detection for SSH relies on the ConnSize analyzer.
|
||||
# Don't do the heuristics if it's disabled.
|
||||
if ( use_conn_size_analyzer )
|
||||
schedule +15secs { ssh_watcher(c) };
|
||||
if ( ( |version| > 3 ) && ( version[4] == "1" ) )
|
||||
c$ssh$version = 1;
|
||||
if ( ( |version| > 3 ) && ( version[4] == "2" ) )
|
||||
c$ssh$version = 2;
|
||||
}
|
||||
|
||||
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 ) )
|
||||
return;
|
||||
|
||||
# We can't accurately tell for compressed streams
|
||||
if ( c$ssh?$compression_alg && ( c$ssh$compression_alg in compression_algorithms ) )
|
||||
return;
|
||||
|
||||
c$ssh$auth_success = T;
|
||||
|
||||
if ( skip_processing_after_detection)
|
||||
{
|
||||
skip_further_processing(c$id);
|
||||
set_record_packets(c$id, F);
|
||||
}
|
||||
}
|
||||
|
||||
event ssh_auth_successful(c: connection, auth_method_none: bool) &priority=-5
|
||||
{
|
||||
if ( c?$ssh && !c$ssh$logged )
|
||||
{
|
||||
c$ssh$logged = T;
|
||||
Log::write(SSH::LOG, c$ssh);
|
||||
}
|
||||
}
|
||||
|
||||
event ssh_auth_failed(c: connection) &priority=5
|
||||
{
|
||||
if ( !c?$ssh || ( c$ssh?$auth_success && !c$ssh$auth_success ) )
|
||||
return;
|
||||
|
||||
# We can't accurately tell for compressed streams
|
||||
if ( c$ssh?$compression_alg && ( c$ssh$compression_alg in compression_algorithms ) )
|
||||
return;
|
||||
|
||||
c$ssh$auth_success = F;
|
||||
c$ssh$num_failures += 1;
|
||||
}
|
||||
|
||||
# Determine the negotiated algorithm
|
||||
function find_alg(client_algorithms: vector of string, server_algorithms: vector of string): string
|
||||
{
|
||||
for ( i in client_algorithms )
|
||||
for ( j in server_algorithms )
|
||||
if ( client_algorithms[i] == server_algorithms[j] )
|
||||
return client_algorithms[i];
|
||||
return "Algorithm negotiation failed";
|
||||
}
|
||||
|
||||
# This is a simple wrapper around find_alg for cases where client to server and server to client
|
||||
# negotiate different algorithms. This is rare, but provided for completeness.
|
||||
function find_bidirectional_alg(client_prefs: Algorithm_Prefs, server_prefs: Algorithm_Prefs): string
|
||||
{
|
||||
local c_to_s = find_alg(client_prefs$client_to_server, server_prefs$client_to_server);
|
||||
local s_to_c = find_alg(client_prefs$server_to_client, server_prefs$server_to_client);
|
||||
|
||||
# Usually these are the same, but if they're not, return the details
|
||||
return c_to_s == s_to_c ? c_to_s : fmt("To server: %s, to client: %s", c_to_s, s_to_c);
|
||||
}
|
||||
|
||||
event ssh_capabilities(c: connection, cookie: string, capabilities: Capabilities)
|
||||
{
|
||||
if ( !c?$ssh || ( c$ssh?$capabilities && c$ssh$capabilities$is_server == capabilities$is_server ) )
|
||||
return;
|
||||
|
||||
if ( !c$ssh?$capabilities )
|
||||
{
|
||||
c$ssh$capabilities = capabilities;
|
||||
return;
|
||||
}
|
||||
|
||||
local client_caps = capabilities$is_server ? c$ssh$capabilities : capabilities;
|
||||
local server_caps = capabilities$is_server ? capabilities : c$ssh$capabilities;
|
||||
|
||||
c$ssh$cipher_alg = find_bidirectional_alg(client_caps$encryption_algorithms,
|
||||
server_caps$encryption_algorithms);
|
||||
c$ssh$mac_alg = find_bidirectional_alg(client_caps$mac_algorithms,
|
||||
server_caps$mac_algorithms);
|
||||
c$ssh$compression_alg = find_bidirectional_alg(client_caps$compression_algorithms,
|
||||
server_caps$compression_algorithms);
|
||||
c$ssh$kex_alg = find_alg(client_caps$kex_algorithms, server_caps$kex_algorithms);
|
||||
c$ssh$host_key_alg = find_alg(client_caps$server_host_key_algorithms,
|
||||
server_caps$server_host_key_algorithms);
|
||||
}
|
||||
|
||||
event connection_state_remove(c: connection) &priority=-5
|
||||
{
|
||||
if ( c?$ssh && !c$ssh$logged && c$ssh?$client && c$ssh?$server )
|
||||
{
|
||||
c$ssh$logged = T;
|
||||
Log::write(SSH::LOG, c$ssh);
|
||||
}
|
||||
}
|
||||
|
||||
function generate_fingerprint(c: connection, key: string)
|
||||
{
|
||||
if ( !c?$ssh )
|
||||
return;
|
||||
|
||||
local lx = str_split(md5_hash(key), vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30));
|
||||
lx[0] = "";
|
||||
c$ssh$host_key = sub(join_string_vec(lx, ":"), /:/, "");
|
||||
}
|
||||
|
||||
event ssh1_server_host_key(c: connection, p: string, e: string) &priority=5
|
||||
{
|
||||
generate_fingerprint(c, e + p);
|
||||
}
|
||||
|
||||
event ssh2_server_host_key(c: connection, key: string) &priority=5
|
||||
{
|
||||
generate_fingerprint(c, key);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,11 @@ export {
|
|||
const TLSv10 = 0x0301;
|
||||
const TLSv11 = 0x0302;
|
||||
const TLSv12 = 0x0303;
|
||||
|
||||
const DTLSv10 = 0xFEFF;
|
||||
# DTLSv11 does not exist
|
||||
const DTLSv12 = 0xFEFD;
|
||||
|
||||
## Mapping between the constants and string values for SSL/TLS versions.
|
||||
const version_strings: table[count] of string = {
|
||||
[SSLv2] = "SSLv2",
|
||||
|
@ -13,6 +18,8 @@ export {
|
|||
[TLSv10] = "TLSv10",
|
||||
[TLSv11] = "TLSv11",
|
||||
[TLSv12] = "TLSv12",
|
||||
[DTLSv10] = "DTLSv10",
|
||||
[DTLSv12] = "DTLSv12"
|
||||
} &default=function(i: count):string { return fmt("unknown-%d", i); };
|
||||
|
||||
## TLS content types:
|
||||
|
|
|
@ -13,3 +13,10 @@ signature dpd_ssl_client {
|
|||
payload /^(\x16\x03[\x00\x01\x02\x03]..\x01...\x03[\x00\x01\x02\x03]|...?\x01[\x00\x03][\x00\x01\x02\x03]).*/
|
||||
tcp-state originator
|
||||
}
|
||||
|
||||
signature dpd_dtls_client {
|
||||
ip-proto == udp
|
||||
# Client hello.
|
||||
payload /^\x16\xfe[\xff\xfd]\x00\x00\x00\x00\x00\x00\x00...\x01...........\xfe[\xff\xfd].*/
|
||||
enable "dtls"
|
||||
}
|
||||
|
|
|
@ -85,6 +85,10 @@ event bro_init() &priority=5
|
|||
Files::register_protocol(Analyzer::ANALYZER_SSL,
|
||||
[$get_file_handle = SSL::get_file_handle,
|
||||
$describe = SSL::describe_file]);
|
||||
|
||||
Files::register_protocol(Analyzer::ANALYZER_DTLS,
|
||||
[$get_file_handle = SSL::get_file_handle,
|
||||
$describe = SSL::describe_file]);
|
||||
}
|
||||
|
||||
event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priority=5
|
||||
|
|
|
@ -92,16 +92,22 @@ redef record Info += {
|
|||
delay_tokens: set[string] &optional;
|
||||
};
|
||||
|
||||
const ports = {
|
||||
const ssl_ports = {
|
||||
443/tcp, 563/tcp, 585/tcp, 614/tcp, 636/tcp,
|
||||
989/tcp, 990/tcp, 992/tcp, 993/tcp, 995/tcp, 5223/tcp
|
||||
};
|
||||
redef likely_server_ports += { ports };
|
||||
|
||||
# There are no well known DTLS ports at the moment. Let's
|
||||
# just add 443 for now for good measure - who knows :)
|
||||
const dtls_ports = { 443/udp };
|
||||
|
||||
redef likely_server_ports += { ssl_ports, dtls_ports };
|
||||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(SSL::LOG, [$columns=Info, $ev=log_ssl]);
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_SSL, ports);
|
||||
Log::create_stream(SSL::LOG, [$columns=Info, $ev=log_ssl, $path="ssl"]);
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_SSL, ssl_ports);
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_DTLS, dtls_ports);
|
||||
}
|
||||
|
||||
function set_session(c: connection)
|
||||
|
@ -268,7 +274,7 @@ event connection_state_remove(c: connection) &priority=-5
|
|||
|
||||
event protocol_confirmation(c: connection, atype: Analyzer::Tag, aid: count) &priority=5
|
||||
{
|
||||
if ( atype == Analyzer::ANALYZER_SSL )
|
||||
if ( atype == Analyzer::ANALYZER_SSL || atype == Analyzer::ANALYZER_DTLS )
|
||||
{
|
||||
set_session(c);
|
||||
c$ssl$analyzer_id = aid;
|
||||
|
@ -278,6 +284,6 @@ event protocol_confirmation(c: connection, atype: Analyzer::Tag, aid: count) &pr
|
|||
event protocol_violation(c: connection, atype: Analyzer::Tag, aid: count,
|
||||
reason: string) &priority=5
|
||||
{
|
||||
if ( c?$ssl )
|
||||
if ( c?$ssl && ( atype == Analyzer::ANALYZER_SSL || atype == Analyzer::ANALYZER_DTLS ) )
|
||||
finish(c, T);
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -35,7 +35,7 @@ redef likely_server_ports += { ports };
|
|||
|
||||
event bro_init() &priority=5
|
||||
{
|
||||
Log::create_stream(Syslog::LOG, [$columns=Info]);
|
||||
Log::create_stream(Syslog::LOG, [$columns=Info, $path="syslog"]);
|
||||
Analyzer::register_for_ports(Analyzer::ANALYZER_SYSLOG, ports);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue