Refine transaction2 support, rewrite SMB scripts.

This commit is contained in:
Vlad Grigorescu 2014-10-07 16:31:02 -04:00
parent 06dffb592b
commit a6de23aaa3
10 changed files with 428 additions and 266 deletions

View file

@ -2635,6 +2635,34 @@ export {
security_blob : string &optional; security_blob : string &optional;
}; };
type SMB1::Find_First2_Request_Args: record {
## File attributes to apply as a constraint to the search
search_attrs : string;
## Max search results
search_count : count;
## Misc. flags for how the server should manage the transaction
## once results are returned
flags : count;
## How detailed the information returned in the results should be
info_level : count;
## Specify whether to search for directories or files
search_storage_type : count;
## The string to serch for (note: may contain wildcards)
file_name : string;
};
type SMB1::Find_First2_Response_Args: record {
## The server generated search identifier
sid : count;
## Number of results returned by the search
search_count : count;
## Whether or not the search can be continued using
## the TRANS2_FIND_NEXT2 transaction
end_of_search : bool;
## An extended attribute name that couldn't be retrieved
ext_attr_error : string &optional;
};
} }

View file

@ -9,6 +9,23 @@ export {
const statuses: table[count] of StatusCode = { const statuses: table[count] of StatusCode = {
[0x00000000] = [$id="SUCCESS", $desc="The operation completed successfully."], [0x00000000] = [$id="SUCCESS", $desc="The operation completed successfully."],
} &redef &default=function(i: count):StatusCode { local unknown=fmt("unknown-%d", i); return [$id=unknown, $desc=unknown]; }; } &redef &default=function(i: count):StatusCode { local unknown=fmt("unknown-%d", i); return [$id=unknown, $desc=unknown]; };
## These are files names that are used for special
## cases by the file system and would not be
## considered "normal" files.
const pipe_names: set[string] = {
"\\netdfs",
"\\spoolss",
"\\NETLOGON",
"\\winreg",
"\\lsarpc",
"\\samr",
"\\srvsvc",
"srvsvc",
"MsFteWds",
"\\wkssvc",
};
} }
module SMB1; module SMB1;
@ -88,6 +105,26 @@ export {
[0xD9] = "WRITE_BULK", [0xD9] = "WRITE_BULK",
[0xDA] = "WRITE_BULK_DATA", [0xDA] = "WRITE_BULK_DATA",
} &default=function(i: count):string { return fmt("unknown-%d", i); }; } &default=function(i: count):string { return fmt("unknown-%d", i); };
const trans2_sub_commands: table[count] of string = {
[0x00] = "OPEN2",
[0x01] = "FIND_FIRST2",
[0x02] = "FIND_NEXT2",
[0x03] = "QUERY_FS_INFORMATION",
[0x04] = "SET_FS_INFORMATION",
[0x05] = "QUERY_PATH_INFORMATION",
[0x06] = "SET_PATH_INFORMATION",
[0x07] = "QUERY_FILE_INFORMATION",
[0x08] = "SET_FILE_INFORMATION",
[0x09] = "FSCTL",
[0x0A] = "IOCTL",
[0x0B] = "FIND_NOTIFY_FIRST",
[0x0C] = "FIND_NOTIFY_NEXT",
[0x0D] = "CREATE_DIRECTORY",
[0x0E] = "SESSION_SETUP",
[0x10] = "GET_DFS_REFERRAL",
[0x11] = "REPORT_DFS_INCONSISTENCY",
} &default=function(i: count):string { return fmt("unknown-trans2-sub-cmd-%d", i); };
} }
module SMB2; module SMB2;

View file

@ -12,15 +12,15 @@ export {
function get_file_handle(c: connection, is_orig: bool): string function get_file_handle(c: connection, is_orig: bool): string
{ {
if ( ! (c$smb?$current_file && if ( ! (c$smb_state?$current_file &&
((c$smb$current_file?$name && c$smb$current_file$name !in pipe_names) || ((c$smb_state$current_file?$name && c$smb_state$current_file$name !in pipe_names) ||
c$smb$current_file?$path)) ) c$smb_state$current_file?$path)) )
{ {
# TODO: figure out what are the cases where this happens. # TODO - figure out what are the cases where this happens.
return ""; return "";
} }
local current_file = c$smb$current_file; local current_file = c$smb_state$current_file;
local path_name = current_file?$path ? current_file$path : ""; local path_name = current_file?$path ? current_file$path : "";
local file_name = current_file?$name ? current_file$name : ""; local file_name = current_file?$name ? current_file$name : "";
# Include last_mod time if available because if a file has been modified it # Include last_mod time if available because if a file has been modified it
@ -38,8 +38,8 @@ function describe_file(f: fa_file): string
for ( cid in f$conns ) for ( cid in f$conns )
{ {
local info = f$conns[cid]; local info = f$conns[cid];
if ( info?$smb && info$smb?$current_file && info$smb$current_file?$name ) if ( info?$smb_state && info$smb_state?$current_file && info$smb_state$current_file?$name )
return info$smb$current_file$name; return info$smb_state$current_file$name;
} }
return ""; return "";
} }
@ -53,11 +53,11 @@ event bro_init() &priority=5
event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priority=5 event file_over_new_connection(f: fa_file, c: connection, is_orig: bool) &priority=5
{ {
if ( c?$smb && c$smb?$current_file ) if ( c?$smb_state && c$smb_state?$current_file )
{ {
c$smb$current_file$fuid = f$id; c$smb_state$current_file$fuid = f$id;
if ( c$smb$current_file?$name ) if ( c$smb_state$current_file?$name )
f$info$filename = c$smb$current_file$name; f$info$filename = c$smb_state$current_file$name;
} }
} }

View file

@ -1,3 +1,5 @@
@load ./consts
module SMB; module SMB;
export { export {
@ -16,68 +18,86 @@ export {
FILE_UNKNOWN, FILE_UNKNOWN,
}; };
## The file actions which are logged.
const logged_file_actions: set[FileAction] = { const logged_file_actions: set[FileAction] = {
FILE_OPEN, FILE_OPEN,
FILE_READ, FILE_READ,
FILE_WRITE, FILE_WRITE,
}; } &redef;
## These are files names that are used for special ## The server response statuses which are *not* logged.
## cases by the file system and would not be const ignored_command_statuses: set[string] = {
## considered "normal" files. "MORE_PROCESSING_REQUIRED",
const pipe_names: set[string] = { } &redef;
"\\netdfs",
"\\spoolss",
"\\NETLOGON",
"\\winreg",
"\\lsarpc",
"\\samr",
"\\srvsvc",
"srvsvc",
"MsFteWds",
"\\wkssvc",
};
## This record is for the smb_files.log
type FileInfo: record { type FileInfo: record {
## Time when the file was first discovered. ## Time when the file was first discovered.
ts : time &log; ts : time &log;
## Unique ID of the connection the file was sent over.
uid : string &log; uid : string &log;
## ID of the connection the file was sent over.
id : conn_id &log; id : conn_id &log;
fuid : string &log; ## Unique ID of the file.
fuid : string &log &optional;
## Action this log record represents. ## Action this log record represents.
action : FileAction &log &default=FILE_UNKNOWN; action : FileAction &log &default=FILE_UNKNOWN;
## Path pulled from the tree this file was transferred to or from. ## Path pulled from the tree this file was transferred to or from.
path : string &log &optional; path : string &log &optional;
## Filename if one was seen. ## Filename if one was seen.
name : string &log &optional; name : string &log &optional;
## Total size of the file. ## Total size of the file.
size : count &log &default=0; size : count &log &default=0;
## Last time this file was modified. ## Last time this file was modified.
times : SMB::MACTimes &log &optional; times : SMB::MACTimes &log &optional;
}; };
## This record is for the smb_mapping.log
type TreeInfo: record { type TreeInfo: record {
## Time when the tree was mapped. ## Time when the tree was mapped.
ts : time &log &optional; ts : time &log &optional;
## Unique ID of the connection the tree was mapped over.
uid : string &log; uid : string &log;
## ID of the connection the tree was mapped over.
id : conn_id &log; id : conn_id &log;
## Name of the tree path. ## Name of the tree path.
path : string &log &optional; path : string &log &optional;
## The type of resource of the tree (disk share, printer share, named pipe, etc.)
service : string &log &optional; service : string &log &optional;
## File system of the tree.
native_file_system : string &log &optional; native_file_system : string &log &optional;
## If this is SMB2, a share type will be included. ## If this is SMB2, a share type will be included.
share_type : string &log &optional; share_type : string &log &optional;
}; };
## This record is for the smb_cmd.log
type CmdInfo: record { type CmdInfo: record {
## The command. ## Timestamp of the command request
command : string &optional; ts : time &log;
## Unique ID of the connection the request was sent over
uid : string &log;
## ID of the connection the request was sent over
id : conn_id &log;
## The command sent by the client
command : string &log;
## The subcommand sent by the client, if present
sub_command : string &log &optional;
## Command argument sent by the client, if any
argument : string &log &optional;
## Server reply to the client's command
status : string &log &optional;
## Round trip time from the request to the response.
rtt : interval &log &optional;
## Version of SMB for the command
version : string &log;
## If this is related to a tree, this is the tree
## that was used for the current command.
tree : string &log &optional;
## If the command referenced a file, store it here. ## If the command referenced a file, store it here.
referenced_file : FileInfo &optional; referenced_file : FileInfo &optional;
@ -85,36 +105,13 @@ export {
referenced_tree : TreeInfo &optional; referenced_tree : TreeInfo &optional;
}; };
type Info: record { ## This record stores the SMB state of in-flight commands,
ts: time &log; ## the file and tree map of the connection.
uid: string &log; type State: record {
id: conn_id &log;
## Version of SMB for the command.
version: string &log;
## Command sent by the client.
command: string &log &optional;
## Server reply to the client's command
status: string &log &optional;
## If this is related to a tree, this is the tree
## that was used for the current command.
tree: string &log &optional;
## The negotiated dialect for the connection.
dialect: string &log &optional;
## Round trip time from the request to the response.
rtt: interval &log &optional;
## A reference to the current command. ## A reference to the current command.
current_cmd : CmdInfo &optional; current_cmd : CmdInfo &optional;
## A reference to the current file. ## A reference to the current file.
current_file : FileInfo &optional; current_file : FileInfo &optional;
## A reference to the current tree. ## A reference to the current tree.
current_tree : TreeInfo &optional; current_tree : TreeInfo &optional;
@ -127,20 +124,22 @@ export {
}; };
redef record connection += { redef record connection += {
smb : Info &optional; smb_state : State &optional;
};
## Internal use only
## Some commands shouldn't be logged by the smb1_message event
const deferred_logging_cmds: set[string] = {
"NEGOTIATE",
}; };
## This is an internally used function. ## This is an internally used function.
const set_current_file: function(smb: Info, file_id: count) &redef; const set_current_file: function(smb_state: State, file_id: count) &redef;
## This is an internally used function. ## This is an internally used function.
const write_file_log: function(f: FileInfo) &redef; const write_file_log: function(f: FileInfo) &redef;
} }
redef record connection += {
smb_pending_cmds : table[count, count] of Info &default=table();
};
redef record FileInfo += { redef record FileInfo += {
## ID referencing this file. ## ID referencing this file.
fid : count &optional; fid : count &optional;
@ -154,22 +153,22 @@ redef likely_server_ports += { ports };
event bro_init() &priority=5 event bro_init() &priority=5
{ {
Log::create_stream(CMD_LOG, [$columns=SMB::Info]); Log::create_stream(CMD_LOG, [$columns=SMB::CmdInfo]);
Log::create_stream(FILES_LOG, [$columns=SMB::FileInfo]); Log::create_stream(FILES_LOG, [$columns=SMB::FileInfo]);
Log::create_stream(MAPPING_LOG, [$columns=SMB::TreeInfo]); Log::create_stream(MAPPING_LOG, [$columns=SMB::TreeInfo]);
Analyzer::register_for_ports(Analyzer::ANALYZER_SMB, ports); Analyzer::register_for_ports(Analyzer::ANALYZER_SMB, ports);
} }
function set_current_file(smb: Info, file_id: count) function set_current_file(smb_state: State, file_id: count)
{ {
if ( file_id !in smb$fid_map ) if ( file_id !in smb_state$fid_map )
{ {
smb$fid_map[file_id] = smb$current_cmd$referenced_file; smb_state$fid_map[file_id] = smb_state$current_cmd$referenced_file;
smb$fid_map[file_id]$fid = file_id; smb_state$fid_map[file_id]$fid = file_id;
} }
smb$current_file = smb$fid_map[file_id]; smb_state$current_file = smb_state$fid_map[file_id];
} }
function write_file_log(f: FileInfo) function write_file_log(f: FileInfo)
@ -190,9 +189,9 @@ event file_state_remove(f: fa_file) &priority=-5
for ( id in f$conns ) for ( id in f$conns )
{ {
local c = f$conns[id]; local c = f$conns[id];
if ( c?$smb && c$smb?$current_file) if ( c?$smb_state && c$smb_state?$current_file)
{ {
write_file_log(c$smb$current_file); write_file_log(c$smb_state$current_file);
} }
return; return;
} }

View file

@ -1,194 +1,216 @@
module SMB1; module SMB1;
redef record SMB::Info += { redef record SMB::CmdInfo += {
## Dialects offered by the client
smb1_offered_dialects: string_vec &optional; smb1_offered_dialects: string_vec &optional;
}; };
event smb1_message(c: connection, hdr: SMB1::Header, is_orig: bool) &priority=5 event smb1_message(c: connection, hdr: SMB1::Header, is_orig: bool) &priority=5
{ {
if ( ! c?$smb ) if ( ! c?$smb_state )
{ {
local info: SMB::Info = [$ts=network_time(), $uid=c$uid, $id=c$id, $version="SMB1"]; local state: SMB::State;
info$fid_map = table(); state$fid_map = table();
info$tid_map = table(); state$tid_map = table();
info$pending_cmds = table(); state$pending_cmds = table();
c$smb = info; c$smb_state = state;
} }
local smb = c$smb; local smb_state = c$smb_state;
local tid = hdr$tid; local tid = hdr$tid;
local pid = hdr$pid; local pid = hdr$pid;
local uid = hdr$uid; local uid = hdr$uid;
local mid = hdr$mid; local mid = hdr$mid;
if ( tid !in smb$tid_map ) if ( tid !in smb_state$tid_map )
{ {
local tmp_tree: SMB::TreeInfo = [$uid=c$uid, $id=c$id]; local tmp_tree: SMB::TreeInfo = [$uid=c$uid, $id=c$id];
smb$tid_map[tid] = tmp_tree; smb_state$tid_map[tid] = tmp_tree;
} }
smb$current_tree = smb$tid_map[tid]; smb_state$current_tree = smb_state$tid_map[tid];
if ( mid !in smb$pending_cmds ) if ( mid !in smb_state$pending_cmds )
{ {
local tmp_cmd: SMB::CmdInfo; local tmp_cmd: SMB::CmdInfo = [$ts=network_time(), $uid=c$uid, $id=c$id, $version="SMB1", $command = SMB1::commands[hdr$command]];
tmp_cmd$command = SMB1::commands[hdr$command];
local tmp_file: SMB::FileInfo; local tmp_file: SMB::FileInfo = [$ts=network_time(), $uid=c$uid, $id=c$id];
tmp_file$ts = network_time();
tmp_file$id = c$id;
tmp_file$uid = c$uid;
tmp_cmd$referenced_file = tmp_file; tmp_cmd$referenced_file = tmp_file;
tmp_cmd$referenced_tree = smb$current_tree; tmp_cmd$referenced_tree = smb_state$current_tree;
smb$pending_cmds[mid] = tmp_cmd; smb_state$pending_cmds[mid] = tmp_cmd;
} }
smb$current_cmd = smb$pending_cmds[mid]; smb_state$current_cmd = smb_state$pending_cmds[mid];
smb$command = smb$current_cmd$command;
if ( is_orig ) if ( !is_orig )
{ {
smb$ts = network_time(); smb_state$current_cmd$rtt = network_time() - smb_state$current_cmd$ts;
} smb_state$current_cmd$status = SMB::statuses[hdr$status]$id;
else
{
smb$rtt = network_time() - smb$ts;
smb$status = SMB::statuses[hdr$status]$id;
} }
} }
event smb1_message(c: connection, hdr: SMB1::Header, is_orig: bool) &priority=-5 event smb1_message(c: connection, hdr: SMB1::Header, is_orig: bool) &priority=-5
{ {
# Is this a response?
if ( !is_orig ) if ( !is_orig )
# This is a response and the command is no longer pending {
# so let's get rid of it. if ( ( c$smb_state$current_cmd$status !in SMB::ignored_command_statuses ) &&
delete c$smb$pending_cmds[hdr$mid]; ( c$smb_state$current_cmd$command !in SMB::deferred_logging_cmds ) )
{
Log::write(SMB::CMD_LOG, c$smb_state$current_cmd);
}
delete c$smb_state$pending_cmds[hdr$mid];
}
}
if ( c?$smb )
Log::write(SMB::CMD_LOG, c$smb); event smb1_transaction2_request(c: connection, hdr: SMB1::Header, sub_cmd: count)
{
c$smb_state$current_cmd$sub_command = SMB1::trans2_sub_commands[sub_cmd];
} }
event smb1_negotiate_request(c: connection, hdr: SMB1::Header, dialects: string_vec) &priority=5 event smb1_negotiate_request(c: connection, hdr: SMB1::Header, dialects: string_vec) &priority=5
{ {
c$smb$smb1_offered_dialects = dialects; c$smb_state$current_cmd$smb1_offered_dialects = dialects;
} }
event smb1_negotiate_response(c: connection, hdr: SMB1::Header, response: SMB1::NegotiateResponse) &priority=5 event smb1_negotiate_response(c: connection, hdr: SMB1::Header, response: SMB1::NegotiateResponse) &priority=5
{ {
if ( c$smb?$smb1_offered_dialects ) if ( c$smb_state$current_cmd?$smb1_offered_dialects )
{ {
if ( response?$ntlm ) if ( response?$ntlm )
c$smb$dialect = c$smb$smb1_offered_dialects[response$ntlm$dialect_index]; {
delete c$smb$smb1_offered_dialects; c$smb_state$current_cmd$argument = c$smb_state$current_cmd$smb1_offered_dialects[response$ntlm$dialect_index];
}
delete c$smb_state$current_cmd$smb1_offered_dialects;
}
}
event smb1_negotiate_response(c: connection, hdr: SMB1::Header, response: SMB1::NegotiateResponse) &priority=-5
{
if ( c$smb_state$current_cmd$status !in SMB::ignored_command_statuses )
{
Log::write(SMB::CMD_LOG, c$smb_state$current_cmd);
} }
} }
event smb1_tree_connect_andx_request(c: connection, hdr: SMB1::Header, path: string, service: string) &priority=5 event smb1_tree_connect_andx_request(c: connection, hdr: SMB1::Header, path: string, service: string) &priority=5
{ {
c$smb$current_cmd$referenced_tree$path = path; local tmp_tree: SMB::TreeInfo = [$ts=network_time(), $uid=c$uid, $id=c$id, $path=path, $service=service];
c$smb$current_cmd$referenced_tree$service = service;
c$smb$current_tree$ts=network_time(); c$smb_state$current_cmd$referenced_tree = tmp_tree;
c$smb_state$current_cmd$argument = path;
} }
event smb1_tree_connect_andx_response(c: connection, hdr: SMB1::Header, service: string, native_file_system: string) &priority=5 event smb1_tree_connect_andx_response(c: connection, hdr: SMB1::Header, service: string, native_file_system: string) &priority=5
{ {
c$smb$current_cmd$referenced_tree$native_file_system = native_file_system; c$smb_state$current_cmd$referenced_tree$native_file_system = native_file_system;
c$smb$current_tree = c$smb$current_cmd$referenced_tree; c$smb_state$current_tree = c$smb_state$current_cmd$referenced_tree;
c$smb$tid_map[hdr$tid] = c$smb$current_tree; c$smb_state$tid_map[hdr$tid] = c$smb_state$current_tree;
} }
event smb1_tree_connect_andx_response(c: connection, hdr: SMB1::Header, service: string, native_file_system: string) &priority=-5 event smb1_tree_connect_andx_response(c: connection, hdr: SMB1::Header, service: string, native_file_system: string) &priority=-5
{ {
Log::write(SMB::MAPPING_LOG, c$smb$current_tree); Log::write(SMB::MAPPING_LOG, c$smb_state$current_tree);
} }
event smb1_nt_create_andx_request(c: connection, hdr: SMB1::Header, name: string) &priority=5 event smb1_nt_create_andx_request(c: connection, hdr: SMB1::Header, name: string) &priority=5
{ {
c$smb$current_cmd$referenced_file$name = name; local tmp_file: SMB::FileInfo = [$ts=network_time(), $uid=c$uid, $id=c$id];
c$smb$current_file = c$smb$current_cmd$referenced_file; c$smb_state$current_cmd$referenced_file = tmp_file;
c$smb$current_file$action = SMB::FILE_OPEN; c$smb_state$current_cmd$referenced_file$name = name;
c$smb_state$current_cmd$referenced_file$action = SMB::FILE_OPEN;
c$smb_state$current_file = c$smb_state$current_cmd$referenced_file;
} }
event smb1_nt_create_andx_response(c: connection, hdr: SMB1::Header, file_id: count, file_size: count, times: SMB::MACTimes) &priority=5 event smb1_nt_create_andx_response(c: connection, hdr: SMB1::Header, file_id: count, file_size: count, times: SMB::MACTimes) &priority=5
{ {
if ( ! c$smb?$current_file ) c$smb_state$current_cmd$referenced_file$action = SMB::FILE_OPEN;
{ c$smb_state$current_cmd$referenced_file$fid = file_id;
c$smb$current_file = c$smb$current_cmd$referenced_file; c$smb_state$current_cmd$referenced_file$size = file_size;
c$smb$current_file$action = SMB::FILE_OPEN;
}
c$smb$current_file$fid = file_id;
c$smb$current_file$size = file_size;
# I'm seeing negative data from IPC tree transfers # I'm seeing negative data from IPC tree transfers
if ( time_to_double(times$modified) > 0.0 ) if ( time_to_double(times$modified) > 0.0 )
c$smb$current_file$times = times; c$smb_state$current_cmd$referenced_file$times = times;
# We can identify the file by its file id now so let's stick it # We can identify the file by its file id now so let's stick it
# in the file map. # in the file map.
c$smb$fid_map[file_id] = c$smb$current_file; c$smb_state$fid_map[file_id] = c$smb_state$current_cmd$referenced_file;
SMB::write_file_log(c$smb$current_file); c$smb_state$current_file = c$smb_state$fid_map[file_id];
SMB::write_file_log(c$smb_state$current_file);
} }
event smb1_read_andx_request(c: connection, hdr: SMB1::Header, file_id: count, offset: count, length: count) &priority=5 event smb1_read_andx_request(c: connection, hdr: SMB1::Header, file_id: count, offset: count, length: count) &priority=5
{ {
SMB::set_current_file(c$smb, file_id); SMB::set_current_file(c$smb_state, file_id);
c$smb$current_file$action = SMB::FILE_READ; c$smb_state$current_file$action = SMB::FILE_READ;
if ( c$smb$current_tree?$path && !c$smb$current_file?$path )
c$smb$current_file$path = c$smb$current_tree$path;
#write_file_log(c$smb$current_file);
} }
event smb1_read_andx_response(c: connection, hdr: SMB1::Header, data_len: count) &priority=5 event smb1_read_andx_request(c: connection, hdr: SMB1::Header, file_id: count, offset: count, length: count) &priority=-5
{ {
#print "read andx response!"; if ( c$smb_state$current_tree?$path && !c$smb_state$current_file?$path )
c$smb_state$current_file$path = c$smb_state$current_tree$path;
# TODO - Why is this commented out?
#write_file_log(c$smb_state$current_file);
} }
#event smb1_read_andx_response(c: connection, hdr: SMB1::Header, data_len: count) &priority=5
# {
# # TODO - determine what to do here
# }
event smb1_write_andx_request(c: connection, hdr: SMB1::Header, file_id: count, offset: count, data_len: count) &priority=5 event smb1_write_andx_request(c: connection, hdr: SMB1::Header, file_id: count, offset: count, data_len: count) &priority=5
{ {
SMB::set_current_file(c$smb, file_id); SMB::set_current_file(c$smb_state, file_id);
c$smb$current_file$action = SMB::FILE_WRITE; c$smb_state$current_file$action = SMB::FILE_WRITE;
} }
event smb1_write_andx_request(c: connection, hdr: SMB1::Header, file_id: count, offset: count, data_len: count) &priority=-5 event smb1_write_andx_request(c: connection, hdr: SMB1::Header, file_id: count, offset: count, data_len: count) &priority=-5
{ {
if ( c$smb$current_tree?$path && !c$smb$current_file?$path ) if ( c$smb_state$current_tree?$path && !c$smb_state$current_file?$path )
c$smb$current_file$path = c$smb$current_tree$path; c$smb_state$current_file$path = c$smb_state$current_tree$path;
#write_file_log(c$smb$current_file); # TODO - Why is this commented out?
#write_file_log(c$smb_state$current_file);
} }
#event smb1_write_andx_response(c: connection, hdr: SMB1::Header, written_bytes: count) &priority=5 #event smb1_write_andx_response(c: connection, hdr: SMB1::Header, written_bytes: count) &priority=5
# { # {
# # Do i really need to do anything here? Maybe do a weird if the number of bytes written is odd? # # TODO - determine what to do here
# } # }
event smb1_close_request(c: connection, hdr: SMB1::Header, file_id: count) &priority=5 event smb1_close_request(c: connection, hdr: SMB1::Header, file_id: count) &priority=5
{ {
SMB::set_current_file(c$smb, file_id); SMB::set_current_file(c$smb_state, file_id);
c$smb$current_file$action = SMB::FILE_CLOSE; c$smb_state$current_file$action = SMB::FILE_CLOSE;
} }
event smb1_close_request(c: connection, hdr: SMB1::Header, file_id: count) &priority=-5 event smb1_close_request(c: connection, hdr: SMB1::Header, file_id: count) &priority=-5
{ {
if ( file_id in c$smb$fid_map ) if ( file_id in c$smb_state$fid_map )
{ {
local fl = c$smb$fid_map[file_id]; local fl = c$smb_state$fid_map[file_id];
fl$uid = c$uid;
fl$id = c$id;
# Need to check for existence of path in case tree connect message wasn't seen. # Need to check for existence of path in case tree connect message wasn't seen.
if ( c$smb$current_tree?$path ) if ( c$smb_state$current_tree?$path )
fl$path = c$smb$current_tree$path; fl$path = c$smb_state$current_tree$path;
delete c$smb$fid_map[file_id]; delete c$smb_state$fid_map[file_id];
SMB::write_file_log(fl); SMB::write_file_log(fl);
} }
else else
{ {
# TODO - Determine correct action
# A reporter message is not right... # A reporter message is not right...
#Reporter::warning("attempting to close an unknown file!"); #Reporter::warning("attempting to close an unknown file!");
} }
} }
event smb1_trans2_get_dfs_referral_request(c: connection, hdr: SMB1::Header, file_name: string, max_referral_level: count)
{
c$smb_state$current_cmd$argument = file_name;
}

View file

@ -1,182 +1,195 @@
module SMB2; module SMB2;
redef record SMB::Info += { redef record SMB::CmdInfo += {
## Dialects offered by the client
smb2_offered_dialects: index_vec &optional; smb2_offered_dialects: index_vec &optional;
}; };
event smb2_message(c: connection, hdr: SMB2::Header, is_orig: bool) &priority=5 event smb2_message(c: connection, hdr: SMB2::Header, is_orig: bool) &priority=5
{ {
if ( ! c?$smb ) if ( ! c?$smb_state )
{ {
local info: SMB::Info = [$ts=network_time(), $uid=c$uid, $id=c$id, $version="SMB2"]; local state: SMB::State;
info$fid_map = table(); state$fid_map = table();
info$tid_map = table(); state$tid_map = table();
info$pending_cmds = table(); state$pending_cmds = table();
c$smb = info; c$smb_state = state;
} }
local smb = c$smb; local smb_state = c$smb_state;
local tid = hdr$tree_id; local tid = hdr$tree_id;
local pid = hdr$process_id; local pid = hdr$process_id;
local mid = hdr$message_id; local mid = hdr$message_id;
local sid = hdr$session_id; local sid = hdr$session_id;
if ( tid !in smb$tid_map ) if ( tid !in smb_state$tid_map )
{ {
local tmp_tree: SMB::TreeInfo = [$uid=c$uid, $id=c$id]; local tmp_tree: SMB::TreeInfo = [$uid=c$uid, $id=c$id];
smb$tid_map[tid] = tmp_tree; smb_state$tid_map[tid] = tmp_tree;
} }
smb$current_tree = smb$tid_map[tid]; smb_state$current_tree = smb_state$tid_map[tid];
if ( mid !in smb$pending_cmds ) if ( mid !in smb_state$pending_cmds )
{ {
local tmp_cmd: SMB::CmdInfo; local tmp_cmd: SMB::CmdInfo = [$ts=network_time(), $uid=c$uid, $id=c$id, $version="SMB2", $command = SMB2::commands[hdr$command]];
tmp_cmd$command = SMB2::commands[hdr$command];
local tmp_file: SMB::FileInfo; local tmp_file: SMB::FileInfo = [$ts=network_time(), $uid=c$uid, $id=c$id];
tmp_file$ts = network_time();
tmp_file$id = c$id;
tmp_file$uid = c$uid;
tmp_cmd$referenced_file = tmp_file; tmp_cmd$referenced_file = tmp_file;
tmp_cmd$referenced_tree = smb$current_tree; tmp_cmd$referenced_tree = smb_state$current_tree;
smb$pending_cmds[mid] = tmp_cmd; smb_state$pending_cmds[mid] = tmp_cmd;
} }
smb$current_cmd = smb$pending_cmds[mid]; smb_state$current_cmd = smb_state$pending_cmds[mid];
smb$command = smb$current_cmd$command;
if ( is_orig ) if ( !is_orig )
{ {
smb$ts = network_time(); smb_state$current_cmd$rtt = network_time() - smb_state$current_cmd$ts;
} smb_state$current_cmd$status = SMB::statuses[hdr$status]$id;
else
{
smb$rtt = network_time() - smb$ts;
smb$status = SMB::statuses[hdr$status]$id;
} }
} }
event smb2_message(c: connection, hdr: SMB2::Header, is_orig: bool) &priority=-5 event smb2_message(c: connection, hdr: SMB2::Header, is_orig: bool) &priority=-5
{ {
# Is this a response?
if ( !is_orig ) if ( !is_orig )
# This is a response and the command is no longer pending {
# so let's get rid of it. if ( ( c$smb_state$current_cmd$status !in SMB::ignored_command_statuses ) &&
delete c$smb$pending_cmds[hdr$message_id]; ( c$smb_state$current_cmd$command !in SMB::deferred_logging_cmds ) )
{
if ( c?$smb ) Log::write(SMB::CMD_LOG, c$smb_state$current_cmd);
Log::write(SMB::CMD_LOG, c$smb); }
delete c$smb_state$pending_cmds[hdr$message_id];
}
} }
event smb2_negotiate_request(c: connection, hdr: SMB2::Header, dialects: index_vec) &priority=5 event smb2_negotiate_request(c: connection, hdr: SMB2::Header, dialects: index_vec) &priority=5
{ {
c$smb$smb2_offered_dialects = dialects; c$smb_state$current_cmd$smb2_offered_dialects = dialects;
} }
event smb2_negotiate_response(c: connection, hdr: SMB2::Header, response: SMB2::NegotiateResponse) event smb2_negotiate_response(c: connection, hdr: SMB2::Header, response: SMB2::NegotiateResponse) &priority=5
{ {
if ( c$smb?$smb2_offered_dialects ) if ( c$smb_state$current_cmd?$smb2_offered_dialects )
{ {
for ( i in c$smb$smb2_offered_dialects ) for ( i in c$smb_state$current_cmd$smb2_offered_dialects )
{ {
if ( response$dialect_revision == c$smb$smb2_offered_dialects[i] ) if ( response$dialect_revision == c$smb_state$current_cmd$smb2_offered_dialects[i] )
{ {
c$smb$dialect = SMB2::dialects[response$dialect_revision]; c$smb_state$current_cmd$argument = SMB2::dialects[response$dialect_revision];
break; break;
} }
} }
delete c$smb$smb2_offered_dialects; delete c$smb_state$current_cmd$smb2_offered_dialects;
}
}
event smb2_negotiate_response(c: connection, hdr: SMB2::Header, response: SMB2::NegotiateResponse) &priority=5
{
if ( c$smb_state$current_cmd$status !in SMB::ignored_command_statuses )
{
Log::write(SMB::CMD_LOG, c$smb_state$current_cmd);
} }
} }
event smb2_tree_connect_request(c: connection, hdr: SMB2::Header, path: string) &priority=5 event smb2_tree_connect_request(c: connection, hdr: SMB2::Header, path: string) &priority=5
{ {
c$smb$current_cmd$referenced_tree$path = path; local tmp_tree: SMB::TreeInfo = [$ts=network_time(), $uid=c$uid, $id=c$id, $path=path];
c$smb$current_tree$ts=network_time();
c$smb_state$current_cmd$referenced_tree = tmp_tree;
} }
event smb2_tree_connect_response(c: connection, hdr: SMB2::Header, response: SMB2::TreeConnectResponse) &priority=5 event smb2_tree_connect_response(c: connection, hdr: SMB2::Header, response: SMB2::TreeConnectResponse) &priority=5
{ {
c$smb$current_tree = c$smb$current_cmd$referenced_tree; c$smb_state$current_cmd$referenced_tree$share_type = SMB2::share_types[response$share_type];
c$smb$current_tree$share_type = SMB2::share_types[response$share_type]; c$smb_state$current_tree = c$smb_state$current_cmd$referenced_tree;
c$smb$tid_map[hdr$tree_id] = c$smb$current_tree; c$smb_state$tid_map[hdr$tree_id] = c$smb_state$current_tree;
} }
event smb2_tree_connect_response(c: connection, hdr: SMB2::Header, response: SMB2::TreeConnectResponse) &priority=-5 event smb2_tree_connect_response(c: connection, hdr: SMB2::Header, response: SMB2::TreeConnectResponse) &priority=-5
{ {
Log::write(SMB::MAPPING_LOG, c$smb$current_tree); Log::write(SMB::MAPPING_LOG, c$smb_state$current_tree);
} }
event smb2_create_request(c: connection, hdr: SMB2::Header, name: string) &priority=5 event smb2_create_request(c: connection, hdr: SMB2::Header, name: string) &priority=5
{ {
c$smb$current_cmd$referenced_file$name = name; local tmp_file: SMB::FileInfo = [$ts=network_time(), $uid=c$uid, $id=c$id];
c$smb$current_file = c$smb$current_cmd$referenced_file; c$smb_state$current_cmd$referenced_file = tmp_file;
c$smb$current_file$action = SMB::FILE_OPEN; c$smb_state$current_cmd$referenced_file$name = name;
c$smb_state$current_cmd$referenced_file$action = SMB::FILE_OPEN;
c$smb_state$current_file = c$smb_state$current_cmd$referenced_file;
} }
event smb2_create_response(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, file_size: count, times: SMB::MACTimes, attrs: SMB2::FileAttrs) &priority=5 event smb2_create_response(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, file_size: count, times: SMB::MACTimes, attrs: SMB2::FileAttrs) &priority=5
{ {
if ( ! c$smb?$current_file ) c$smb_state$current_cmd$referenced_file$action = SMB::FILE_OPEN;
{ c$smb_state$current_cmd$referenced_file$fid = file_id$persistent+file_id$volatile;
c$smb$current_file = c$smb$current_cmd$referenced_file; c$smb_state$current_cmd$referenced_file$size = file_size;
c$smb$current_file$action = SMB::FILE_OPEN;
}
c$smb$current_file$fid = file_id$persistent+file_id$volatile;
c$smb$current_file$size = file_size;
# I'm seeing negative data from IPC tree transfers # I'm seeing negative data from IPC tree transfers
if ( time_to_double(times$modified) > 0.0 ) if ( time_to_double(times$modified) > 0.0 )
c$smb$current_file$times = times; c$smb_state$current_cmd$referenced_file$times = times;
# We can identify the file by its file id now so let's stick it # We can identify the file by its file id now so let's stick it
# in the file map. # in the file map.
c$smb$fid_map[file_id$persistent+file_id$volatile] = c$smb$current_file; c$smb_state$fid_map[file_id$persistent+file_id$volatile] = c$smb_state$current_cmd$referenced_file;
SMB::write_file_log(c$smb$current_file); c$smb_state$current_file = c$smb_state$fid_map[file_id$persistent+file_id$volatile];
SMB::write_file_log(c$smb_state$current_file);
} }
event smb2_read_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, offset: count, length: count) &priority=5 event smb2_read_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, offset: count, length: count) &priority=5
{ {
SMB::set_current_file(c$smb, file_id$persistent+file_id$volatile); SMB::set_current_file(c$smb_state, file_id$persistent+file_id$volatile);
c$smb$current_file$action = SMB::FILE_READ; c$smb_state$current_file$action = SMB::FILE_READ;
}
if ( c$smb$current_tree?$path && !c$smb$current_file?$path ) event smb2_read_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, offset: count, length: count) &priority=-5
c$smb$current_file$path = c$smb$current_tree$path; {
if ( c$smb_state$current_tree?$path && !c$smb_state$current_file?$path )
c$smb_state$current_file$path = c$smb_state$current_tree$path;
#write_file_log(c$smb$current_file); # TODO - Why is this commented out?
#write_file_log(c$smb_state$current_file);
} }
event smb2_write_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, offset: count, length: count) &priority=5 event smb2_write_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, offset: count, length: count) &priority=5
{ {
SMB::set_current_file(c$smb, file_id$persistent+file_id$volatile); SMB::set_current_file(c$smb_state, file_id$persistent+file_id$volatile);
c$smb$current_file$action = SMB::FILE_WRITE; c$smb_state$current_file$action = SMB::FILE_WRITE;
}
if ( c$smb$current_tree?$path && ! c$smb$current_file?$path ) event smb2_write_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID, offset: count, length: count) &priority=-5
c$smb$current_file$path = c$smb$current_tree$path; {
if ( c$smb_state$current_tree?$path && ! c$smb_state$current_file?$path )
c$smb_state$current_file$path = c$smb_state$current_tree$path;
# TODO - Why is this commented out?
#write_file_log(c$smb_state$current_file);
} }
event smb2_close_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID) &priority=5 event smb2_close_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID) &priority=5
{ {
SMB::set_current_file(c$smb, file_id$persistent+file_id$volatile); SMB::set_current_file(c$smb_state, file_id$persistent+file_id$volatile);
c$smb$current_file$action = SMB::FILE_CLOSE; c$smb_state$current_file$action = SMB::FILE_CLOSE;
} }
event smb2_close_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID) &priority=-5 event smb2_close_request(c: connection, hdr: SMB2::Header, file_id: SMB2::GUID) &priority=-5
{ {
if ( file_id$persistent+file_id$volatile in c$smb$fid_map ) if ( file_id$persistent+file_id$volatile in c$smb_state$fid_map )
{ {
local fl = c$smb$fid_map[file_id$persistent+file_id$volatile]; local fl = c$smb_state$fid_map[file_id$persistent+file_id$volatile];
fl$uid = c$uid;
fl$id = c$id;
# Need to check for existence of path in case tree connect message wasn't seen. # Need to check for existence of path in case tree connect message wasn't seen.
if ( c$smb$current_tree?$path ) if ( c$smb_state$current_tree?$path )
fl$path = c$smb$current_tree$path; fl$path = c$smb_state$current_tree$path;
delete c$smb$fid_map[file_id$persistent+file_id$volatile]; delete c$smb_state$fid_map[file_id$persistent+file_id$volatile];
SMB::write_file_log(fl); SMB::write_file_log(fl);
} }
else else
{ {
# TODO - Determine correct action
# A reporter message is not right... # A reporter message is not right...
#Reporter::warning("attempting to close an unknown file!"); #Reporter::warning("attempting to close an unknown file!");
} }

View file

@ -20,6 +20,7 @@ bro_plugin_bif(
smb1_com_query_information.bif smb1_com_query_information.bif
smb1_com_read_andx.bif smb1_com_read_andx.bif
smb1_com_session_setup_andx.bif smb1_com_session_setup_andx.bif
smb1_com_transaction2.bif
smb1_com_tree_connect_andx.bif smb1_com_tree_connect_andx.bif
smb1_com_tree_disconnect.bif smb1_com_tree_disconnect.bif
smb1_com_write_andx.bif smb1_com_write_andx.bif

View file

@ -21,6 +21,7 @@
#include "smb1_com_query_information.bif.h" #include "smb1_com_query_information.bif.h"
#include "smb1_com_read_andx.bif.h" #include "smb1_com_read_andx.bif.h"
#include "smb1_com_session_setup_andx.bif.h" #include "smb1_com_session_setup_andx.bif.h"
#include "smb1_com_transaction2.bif.h"
#include "smb1_com_tree_connect_andx.bif.h" #include "smb1_com_tree_connect_andx.bif.h"
#include "smb1_com_tree_disconnect.bif.h" #include "smb1_com_tree_disconnect.bif.h"
#include "smb1_com_write_andx.bif.h" #include "smb1_com_write_andx.bif.h"

View file

@ -22,13 +22,16 @@ refine connection SMB_Conn += {
function proc_smb1_transaction2_request(header: SMB_Header, val: SMB1_transaction2_request): bool function proc_smb1_transaction2_request(header: SMB_Header, val: SMB1_transaction2_request): bool
%{ %{
//printf("transaction2_request sub command: %d\n", ${val.sub_cmd}); if ( smb1_transaction2_request )
BifEvent::generate_smb1_transaction2_request(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header), ${val.sub_cmd});
return true; return true;
%} %}
function proc_smb1_transaction2_response(header: SMB_Header, val: SMB1_transaction2_response): bool function proc_smb1_transaction2_response(header: SMB_Header, val: SMB1_transaction2_response): bool
%{ %{
//printf("transaction2_response sub command: %d\n", ${val.sub_cmd}); // if ( smb1_transaction2_response )
// BifEvent::generate_smb1_transaction2_response(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header), new Val(${val.sub_cmd}, TYPE_COUNT));
return true; return true;
%} %}
@ -278,8 +281,13 @@ refine connection SMB_Conn += {
function proc_trans2_get_dfs_referral_request(header: SMB_Header, val: trans2_get_dfs_referral_request): bool function proc_trans2_get_dfs_referral_request(header: SMB_Header, val: trans2_get_dfs_referral_request): bool
%{ %{
// TODO: implement this. if ( smb1_trans2_get_dfs_referral_request )
//printf("trans2_get_dfs_referral request!\n"); {
BifEvent::generate_smb1_trans2_get_dfs_referral_request(bro_analyzer(), bro_analyzer()->Conn(), \
BuildHeaderVal(header), \
smb_string2stringval(${val.file_name}),\
${val.max_referral_level});
}
return true; return true;
%} %}

View file

@ -0,0 +1,53 @@
### Requests
# TODO - Description
event smb1_transaction2_request%(c: connection, hdr: SMB1::Header, sub_cmd: count%);
# TODO - Description
event smb1_trans2_find_first2_request%(c: connection, hdr: SMB1::Header, args: SMB1::Find_First2_Request_Args%);
# TODO - Implementation
# event smb1_trans2_fs_info_request%(c: connection, hdr: SMB1::Header, ??? %);
# TODO - Description
event smb1_trans2_query_path_info_request%(c: connection, hdr: SMB1::Header, file_name: string, level_of_interest: count%);
# TODO - Description
event smb1_trans2_query_file_info_request%(c: connection, hdr: SMB1::Header, file_id: count, level_of_interest: count%);
# TODO - Implementation
# event smb1_trans2_set_file_info_request(c: connection, hdr: SMB1::Header, ??? %);
# TODO - Description
event smb1_trans2_get_dfs_referral_request%(c: connection, hdr: SMB1::Header, file_name: string, max_referral_level: count%);
### Responses
# TODO - Description
event smb1_transaction2_response%(c: connection, hdr: SMB1::Header, sub_cmd: count%);
# TODO - Description
event smb1_trans2_find_first2_response%(c: connection, hdr: SMB1::Header, args: SMB1::Find_First2_Response_Args%);
# TODO - Implementation
# event smb1_trans2_fs_info_response%(c: connection, hdr: SMB1::Header, ??? %);
# TODO - Implementation
# event smb1_trans2_query_path_info_response%(c: connection, hdr: SMB1::Header, ??? %);
# TODO - Implementation
# event smb1_trans2_query_file_info_response%(c: connection, hdr: SMB1::Header, ??? %);
# TODO - Implementation
# event smb1_trans2_set_file_info_response%(c: connection, hdr: SMB1::Header, ??? %);
# TODO - Implementation
# event smb1_trans2_get_dfs_referral_response%(c: connection, hdr: SMB1::Header, ??? %);
### Types
type SMB1::Find_First2_Request_Args: record;
type SMB1::Find_First2_Response_Args: record;