mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Hacking the SMB analyzer. Checkpoint.
This commit is contained in:
parent
ac2b507480
commit
1b638eec0c
7 changed files with 353 additions and 105 deletions
|
@ -931,6 +931,8 @@ type smb_hdr : record {
|
||||||
pid: count;
|
pid: count;
|
||||||
uid: count;
|
uid: count;
|
||||||
mid: count;
|
mid: count;
|
||||||
|
first_time: time;
|
||||||
|
last_time: time;
|
||||||
};
|
};
|
||||||
|
|
||||||
type smb_trans : record {
|
type smb_trans : record {
|
||||||
|
|
251
policy/smb.bro
251
policy/smb.bro
|
@ -1,8 +1,255 @@
|
||||||
# $Id:$
|
# $Id:$
|
||||||
|
#
|
||||||
|
|
||||||
|
@load conn-id
|
||||||
|
|
||||||
|
# TODO: capture filter
|
||||||
redef capture_filters += { ["smb"] = "port 445" };
|
redef capture_filters += { ["smb"] = "port 445" };
|
||||||
|
|
||||||
global smb_ports = { 445/tcp } &redef;
|
global smb_ports = { 139/tcp, 445/tcp } &redef;
|
||||||
redef dpd_config += { [ANALYZER_SMB] = [$ports = smb_ports] };
|
redef dpd_config += { [ANALYZER_SMB] = [$ports = smb_ports] };
|
||||||
|
|
||||||
# No default implementation for events.
|
const smb_log = open_log_file("smb") &redef;
|
||||||
|
|
||||||
|
|
||||||
|
type smb_cmd_info: record {
|
||||||
|
pid: count;
|
||||||
|
mid: count;
|
||||||
|
cmd: count;
|
||||||
|
cmdstr: string;
|
||||||
|
|
||||||
|
# hack: for operations involving file ids: note the file id.
|
||||||
|
# this is 16 bit, so we use 0x10000 to indicate that the fid is not
|
||||||
|
# valid
|
||||||
|
fid: count;
|
||||||
|
# for read/writes: number of bytes read/written
|
||||||
|
file_payload: count;
|
||||||
|
|
||||||
|
req_first_time: time;
|
||||||
|
req_last_time: time;
|
||||||
|
req_body_len: count;
|
||||||
|
|
||||||
|
rep_first_time: time;
|
||||||
|
rep_last_time: time;
|
||||||
|
rep_body_len: count;
|
||||||
|
|
||||||
|
done: bool;
|
||||||
|
};
|
||||||
|
|
||||||
|
type smb_pending_cmds: table[count, count] of smb_cmd_info;
|
||||||
|
global smb_sessions: table[conn_id] of smb_pending_cmds;
|
||||||
|
|
||||||
|
# it seems Bro has issues with anonymous records of the form [cid,count]
|
||||||
|
# so we just use a table of table
|
||||||
|
global fid_map: table[conn_id] of table[count] of string;
|
||||||
|
global next_fid = 0;
|
||||||
|
|
||||||
|
# the commands in this set are handled by a more specific event handler
|
||||||
|
# that add additional information. I.e., the smb_message event still does
|
||||||
|
# request/reply matching, but the more specific event takes care of printing.
|
||||||
|
# It's all a hack....
|
||||||
|
global more_specific_cmds: set[count];
|
||||||
|
event bro_init()
|
||||||
|
{
|
||||||
|
add more_specific_cmds[0x2e]; # read_andx
|
||||||
|
add more_specific_cmds[0x2f]; # write_andx
|
||||||
|
}
|
||||||
|
|
||||||
|
function smb_new_cmd_info(hdr: smb_hdr, body_len: count): smb_cmd_info
|
||||||
|
{
|
||||||
|
local info: smb_cmd_info;
|
||||||
|
|
||||||
|
info$cmd = hdr$command;
|
||||||
|
info$pid = hdr$pid;
|
||||||
|
info$mid = hdr$mid;
|
||||||
|
info$cmdstr = "";
|
||||||
|
|
||||||
|
info$fid = 0x10000;
|
||||||
|
info$file_payload = 0;
|
||||||
|
|
||||||
|
info$req_first_time = hdr$first_time;
|
||||||
|
info$req_last_time = hdr$last_time;
|
||||||
|
info$req_body_len = body_len;
|
||||||
|
|
||||||
|
info$rep_first_time = double_to_time(0.0);
|
||||||
|
info$rep_last_time = double_to_time(0.0);
|
||||||
|
info$rep_body_len = 0;
|
||||||
|
|
||||||
|
|
||||||
|
info$done = F;
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_fid(cid: conn_id, fid: count): string
|
||||||
|
{
|
||||||
|
if (cid !in fid_map)
|
||||||
|
fid_map[cid] = table();
|
||||||
|
if ( fid !in fid_map[cid])
|
||||||
|
{
|
||||||
|
if (fid >= 0x10000)
|
||||||
|
return "FIDxx";
|
||||||
|
fid_map[cid][fid] = fmt("FID%d", next_fid);
|
||||||
|
++next_fid;
|
||||||
|
}
|
||||||
|
return fid_map[cid][fid];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function fmt_smb_hdr(hdr: smb_hdr): string
|
||||||
|
{
|
||||||
|
return fmt("%.6f %.6f %d %d %d %d %d", hdr$first_time, hdr$last_time, hdr$tid,
|
||||||
|
hdr$pid, hdr$mid, hdr$uid, hdr$status);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function fmt_msg_prefix(cid: conn_id, is_orig: bool, hdr: smb_hdr): string
|
||||||
|
{
|
||||||
|
return fmt("%s %d (%d) %s", id_string(cid), is_orig, hdr$command,
|
||||||
|
fmt_smb_hdr(hdr));
|
||||||
|
}
|
||||||
|
|
||||||
|
function smb_log_cmd(c: connection, info: smb_cmd_info)
|
||||||
|
{
|
||||||
|
local msg = "";
|
||||||
|
msg = fmt("COMMAND %s (%d) %d:%d %.6f %.6f %d %.6f %.6f %d %s",
|
||||||
|
info$cmdstr, info$cmd, info$pid, info$mid,
|
||||||
|
info$req_first_time, info$req_last_time, info$req_body_len,
|
||||||
|
info$rep_first_time, info$rep_last_time, info$rep_body_len,
|
||||||
|
get_fid(c$id, info$fid));
|
||||||
|
print smb_log, msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
function smb_log_cmd2(c: connection, hdr: smb_hdr)
|
||||||
|
{
|
||||||
|
if (c$id !in smb_sessions)
|
||||||
|
return;
|
||||||
|
local cur_session = smb_sessions[c$id];
|
||||||
|
if ([hdr$pid,hdr$mid] !in cur_session)
|
||||||
|
return;
|
||||||
|
local info = cur_session[hdr$pid, hdr$mid];
|
||||||
|
|
||||||
|
smb_log_cmd(c, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mismatch_fmt_hdr(hdr: smb_hdr, cmd: string): string
|
||||||
|
{
|
||||||
|
return fmt("%s %d:%d", cmd, hdr$pid, hdr$mid);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mismatch_fmt_info(info: smb_cmd_info): string
|
||||||
|
{
|
||||||
|
return fmt("%s %d:%d", info$cmdstr, info$pid, info$mid);
|
||||||
|
}
|
||||||
|
|
||||||
|
function smb_set_fid(cid: conn_id, hdr: smb_hdr, fid: count)
|
||||||
|
{
|
||||||
|
# smb_messge takes care of error / mismatch handling, so we can
|
||||||
|
# just punt here
|
||||||
|
if (cid !in smb_sessions)
|
||||||
|
return;
|
||||||
|
local cur_session = smb_sessions[cid];
|
||||||
|
if ([hdr$pid,hdr$mid] !in cur_session)
|
||||||
|
return;
|
||||||
|
local info = cur_session[hdr$pid, hdr$mid];
|
||||||
|
|
||||||
|
info$fid = fid;
|
||||||
|
}
|
||||||
|
|
||||||
|
function smb_set_file_payload(cid: conn_id, hdr: smb_hdr, payload_len: count)
|
||||||
|
{
|
||||||
|
# smb_messge takes care of error / mismatch handling, so we can
|
||||||
|
# just punt here
|
||||||
|
if (cid !in smb_sessions)
|
||||||
|
return;
|
||||||
|
local cur_session = smb_sessions[cid];
|
||||||
|
if ([hdr$pid,hdr$mid] !in cur_session)
|
||||||
|
return;
|
||||||
|
local info = cur_session[hdr$pid, hdr$mid];
|
||||||
|
|
||||||
|
info$file_payload = payload_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
# note, the smb_message event is raised before and more specific ones, so
|
||||||
|
# we use it to match requests to replies.
|
||||||
|
# A hack, but it works
|
||||||
|
event smb_message(c: connection, hdr: smb_hdr, is_orig: bool, cmd: string, body_length: count, body: string)
|
||||||
|
{
|
||||||
|
###print smb_log, fmt("%s %s %d", fmt_msg_prefix(c$id, is_orig, hdr), cmd, body_length);
|
||||||
|
if (c$id !in smb_sessions)
|
||||||
|
smb_sessions[c$id] = table();
|
||||||
|
local cur_session = smb_sessions[c$id];
|
||||||
|
|
||||||
|
# cleanup and log
|
||||||
|
if ([hdr$pid,hdr$mid] in cur_session)
|
||||||
|
if (cur_session[hdr$pid,hdr$mid]$done)
|
||||||
|
delete cur_session[hdr$pid,hdr$mid];
|
||||||
|
|
||||||
|
if (is_orig)
|
||||||
|
{
|
||||||
|
if ([hdr$pid,hdr$mid] in cur_session)
|
||||||
|
print smb_log, fmt("Mismatch: got a request but already have request queued: %s %s",
|
||||||
|
mismatch_fmt_info(cur_session[hdr$pid,hdr$mid]), mismatch_fmt_hdr(hdr,cmd));
|
||||||
|
cur_session[hdr$pid, hdr$mid] = smb_new_cmd_info(hdr, body_length);
|
||||||
|
cur_session[hdr$pid, hdr$mid]$cmdstr = cmd;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ([hdr$pid,hdr$mid] !in cur_session)
|
||||||
|
print smb_log, fmt("Mismatch: got a reply but no request queued: %s", mismatch_fmt_hdr(hdr,cmd));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
local info = cur_session[hdr$pid, hdr$mid];
|
||||||
|
if (info$cmd != hdr$command)
|
||||||
|
{
|
||||||
|
print smb_log, fmt("Mismatch: request and reply command don't match: %s %s",
|
||||||
|
mismatch_fmt_info(cur_session[hdr$pid,hdr$mid]), mismatch_fmt_hdr(hdr,cmd));
|
||||||
|
delete cur_session[hdr$pid,hdr$mid];
|
||||||
|
}
|
||||||
|
else if (info$mid != hdr$mid || info$pid != hdr$pid)
|
||||||
|
{
|
||||||
|
# This really should not happen
|
||||||
|
print smb_log, fmt("Mismatch: request and reply IDs don't match: %s %s",
|
||||||
|
mismatch_fmt_info(cur_session[hdr$pid,hdr$mid]), mismatch_fmt_hdr(hdr,cmd));
|
||||||
|
delete cur_session[hdr$pid,hdr$mid];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
info$rep_first_time = hdr$first_time;
|
||||||
|
info$rep_last_time = hdr$last_time;
|
||||||
|
info$rep_body_len = body_length;
|
||||||
|
info$done = T;
|
||||||
|
if (hdr$command !in more_specific_cmds)
|
||||||
|
smb_log_cmd(c, info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb_com_read_andx(c: connection, hdr: smb_hdr, fid: count)
|
||||||
|
{
|
||||||
|
smb_set_fid(c$id, hdr, fid);
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb_com_read_andx_response(c: connection, hdr: smb_hdr, len: count)
|
||||||
|
{
|
||||||
|
smb_set_file_payload(c$id, hdr, len);
|
||||||
|
smb_log_cmd2(c, hdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb_com_write_andx(c: connection, hdr: smb_hdr, fid: count, len: count)
|
||||||
|
{
|
||||||
|
smb_set_fid(c$id, hdr, fid);
|
||||||
|
smb_set_file_payload(c$id, hdr, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
event smb_com_write_andx_response(c: connection, hdr: smb_hdr)
|
||||||
|
{
|
||||||
|
smb_log_cmd2(c, hdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
event connection_state_remove(c: connection)
|
||||||
|
{
|
||||||
|
delete smb_sessions[c$id];
|
||||||
|
}
|
||||||
|
|
|
@ -106,7 +106,7 @@ int NetbiosSSN_Interpreter::ParseDatagram(const u_char* data, int len,
|
||||||
{
|
{
|
||||||
if ( smb_session )
|
if ( smb_session )
|
||||||
{
|
{
|
||||||
smb_session->Deliver(is_query, len, data);
|
smb_session->Deliver(is_query, len, data, 0, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ int NetbiosSSN_Interpreter::ParseBroadcast(const u_char* data, int len,
|
||||||
|
|
||||||
if ( smb_session )
|
if ( smb_session )
|
||||||
{
|
{
|
||||||
smb_session->Deliver(is_query, len, data);
|
smb_session->Deliver(is_query, len, data, 0, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +188,7 @@ int NetbiosSSN_Interpreter::ParseSessionMsg(const u_char* data, int len,
|
||||||
|
|
||||||
if ( smb_session )
|
if ( smb_session )
|
||||||
{
|
{
|
||||||
smb_session->Deliver(is_query, len, data);
|
smb_session->Deliver(is_query, len, data, 0, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
156
src/SMB.cc
156
src/SMB.cc
|
@ -11,6 +11,8 @@ namespace {
|
||||||
const bool DEBUG_smb_ipc = true;
|
const bool DEBUG_smb_ipc = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SMB_MAX_LEN (1<<17)
|
||||||
|
|
||||||
#define BYTEORDER_SWAP16(n) ((256 * ((n) & 0xff)) + ((n) >> 8))
|
#define BYTEORDER_SWAP16(n) ((256 * ((n) & 0xff)) + ((n) >> 8))
|
||||||
|
|
||||||
enum SMB_Command {
|
enum SMB_Command {
|
||||||
|
@ -135,10 +137,13 @@ void SMB_Session::set_andx(int is_orig, binpac::SMB::SMB_andx* andx)
|
||||||
andx_[ind] = andx;
|
andx_[ind] = andx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMB_Session::Deliver(int is_orig, int len, const u_char* data)
|
void SMB_Session::Deliver(int is_orig, int len, const u_char* data,
|
||||||
|
double arg_first_time, double arg_last_time)
|
||||||
{
|
{
|
||||||
if ( len == 0 )
|
if ( len == 0 )
|
||||||
return;
|
return;
|
||||||
|
first_time = arg_first_time;
|
||||||
|
last_time = arg_last_time;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -152,8 +157,14 @@ void SMB_Session::Deliver(int is_orig, int len, const u_char* data)
|
||||||
|
|
||||||
int next_command = hdr.command();
|
int next_command = hdr.command();
|
||||||
|
|
||||||
|
fprintf(stderr, "SMB command: %02x %s len %-7d dur %.6lf\n", next_command,
|
||||||
|
SMB_command_name[next_command], len,
|
||||||
|
last_time-first_time);
|
||||||
|
int ncmds = 0;
|
||||||
|
|
||||||
while ( data < data_end )
|
while ( data < data_end )
|
||||||
{
|
{
|
||||||
|
ncmds++;
|
||||||
SMB_Body body(data, data_end);
|
SMB_Body body(data, data_end);
|
||||||
set_andx(is_orig, 0);
|
set_andx(is_orig, 0);
|
||||||
ParseMessage(is_orig, next_command, hdr, body);
|
ParseMessage(is_orig, next_command, hdr, body);
|
||||||
|
@ -172,6 +183,7 @@ void SMB_Session::Deliver(int is_orig, int len, const u_char* data)
|
||||||
|
|
||||||
data = data_start + next;
|
data = data_start + next;
|
||||||
}
|
}
|
||||||
|
fprintf(stderr, "ncmds %d\n", ncmds);
|
||||||
}
|
}
|
||||||
catch ( const binpac::Exception& e )
|
catch ( const binpac::Exception& e )
|
||||||
{
|
{
|
||||||
|
@ -566,7 +578,8 @@ int SMB_Session::ParseReadAndx(binpac::SMB::SMB_header const& hdr,
|
||||||
val_list* vl = new val_list;
|
val_list* vl = new val_list;
|
||||||
vl->append(analyzer->BuildConnVal());
|
vl->append(analyzer->BuildConnVal());
|
||||||
vl->append(BuildHeaderVal(hdr));
|
vl->append(BuildHeaderVal(hdr));
|
||||||
vl->append(new StringVal(""));
|
vl->append(new Val(req.fid(), TYPE_COUNT));
|
||||||
|
//vl->append(new StringVal(""));
|
||||||
|
|
||||||
analyzer->ConnectionEvent(smb_com_read_andx, vl);
|
analyzer->ConnectionEvent(smb_com_read_andx, vl);
|
||||||
}
|
}
|
||||||
|
@ -584,12 +597,13 @@ int SMB_Session::ParseReadAndxResponse(binpac::SMB::SMB_header const& hdr,
|
||||||
int data_count = resp.data_length();
|
int data_count = resp.data_length();
|
||||||
const u_char* data = resp.data().begin();
|
const u_char* data = resp.data().begin();
|
||||||
|
|
||||||
if ( smb_com_read_andx )
|
if ( smb_com_read_andx_response )
|
||||||
{
|
{
|
||||||
val_list* vl = new val_list;
|
val_list* vl = new val_list;
|
||||||
vl->append(analyzer->BuildConnVal());
|
vl->append(analyzer->BuildConnVal());
|
||||||
vl->append(BuildHeaderVal(hdr));
|
vl->append(BuildHeaderVal(hdr));
|
||||||
vl->append(new StringVal(data_count, (const char*) data));
|
vl->append(new Val((resp.data_len_high()<<16)+(resp.data_len()), TYPE_COUNT));
|
||||||
|
//vl->append(new StringVal(data_count, (const char*) data));
|
||||||
|
|
||||||
analyzer->ConnectionEvent(smb_com_read_andx, vl);
|
analyzer->ConnectionEvent(smb_com_read_andx, vl);
|
||||||
}
|
}
|
||||||
|
@ -614,7 +628,9 @@ int SMB_Session::ParseWriteAndx(binpac::SMB::SMB_header const& hdr,
|
||||||
val_list* vl = new val_list;
|
val_list* vl = new val_list;
|
||||||
vl->append(analyzer->BuildConnVal());
|
vl->append(analyzer->BuildConnVal());
|
||||||
vl->append(BuildHeaderVal(hdr));
|
vl->append(BuildHeaderVal(hdr));
|
||||||
vl->append(new StringVal(data_count, (const char*) data));
|
vl->append(new Val(req.fid(), TYPE_COUNT));
|
||||||
|
vl->append(new Val((req.data_len_high()<<16)+(req.data_len()), TYPE_COUNT));
|
||||||
|
//vl->append(new StringVal(data_count, (const char*) data));
|
||||||
|
|
||||||
analyzer->ConnectionEvent(smb_com_write_andx, vl);
|
analyzer->ConnectionEvent(smb_com_write_andx, vl);
|
||||||
}
|
}
|
||||||
|
@ -631,14 +647,14 @@ int SMB_Session::ParseWriteAndxResponse(binpac::SMB::SMB_header const& hdr,
|
||||||
resp.Parse(body.data(), body.data() + body.length());
|
resp.Parse(body.data(), body.data() + body.length());
|
||||||
set_andx(0, resp.andx());
|
set_andx(0, resp.andx());
|
||||||
|
|
||||||
if ( smb_com_write_andx )
|
if ( smb_com_write_andx_response )
|
||||||
{
|
{
|
||||||
val_list* vl = new val_list;
|
val_list* vl = new val_list;
|
||||||
vl->append(analyzer->BuildConnVal());
|
vl->append(analyzer->BuildConnVal());
|
||||||
vl->append(BuildHeaderVal(hdr));
|
vl->append(BuildHeaderVal(hdr));
|
||||||
vl->append(new StringVal(""));
|
//vl->append(new StringVal(""));
|
||||||
|
|
||||||
analyzer->ConnectionEvent(smb_com_write_andx, vl);
|
analyzer->ConnectionEvent(smb_com_write_andx_response, vl);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1016,6 +1032,8 @@ Val* SMB_Session::BuildHeaderVal(binpac::SMB::SMB_header const& hdr)
|
||||||
r->Assign(5, new Val(hdr.pid(), TYPE_COUNT));
|
r->Assign(5, new Val(hdr.pid(), TYPE_COUNT));
|
||||||
r->Assign(6, new Val(hdr.uid(), TYPE_COUNT));
|
r->Assign(6, new Val(hdr.uid(), TYPE_COUNT));
|
||||||
r->Assign(7, new Val(hdr.mid(), TYPE_COUNT));
|
r->Assign(7, new Val(hdr.mid(), TYPE_COUNT));
|
||||||
|
r->Assign(8, new Val(first_time, TYPE_TIME));
|
||||||
|
r->Assign(9, new Val(last_time, TYPE_TIME));
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -1108,23 +1126,16 @@ Contents_SMB::Contents_SMB(Connection* conn, bool orig, SMB_Session* s)
|
||||||
: TCP_SupportAnalyzer(AnalyzerTag::Contents_SMB, conn, orig)
|
: TCP_SupportAnalyzer(AnalyzerTag::Contents_SMB, conn, orig)
|
||||||
{
|
{
|
||||||
smb_session = s;
|
smb_session = s;
|
||||||
msg_buf = 0;
|
state = WAIT_FOR_HDR;
|
||||||
|
first_time = last_time = 0.0;
|
||||||
|
hdr_buf.Init(4,4);
|
||||||
msg_len = 0;
|
msg_len = 0;
|
||||||
buf_len = 0;
|
msg_type = 0;
|
||||||
buf_n = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Contents_SMB::InitMsgBuf()
|
|
||||||
{
|
|
||||||
delete [] msg_buf;
|
|
||||||
msg_buf = new u_char[msg_len];
|
|
||||||
buf_len = msg_len;
|
|
||||||
buf_n = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Contents_SMB::~Contents_SMB()
|
Contents_SMB::~Contents_SMB()
|
||||||
{
|
{
|
||||||
delete [] msg_buf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Contents_SMB::DeliverSMB(int len, const u_char* data)
|
void Contents_SMB::DeliverSMB(int len, const u_char* data)
|
||||||
|
@ -1132,93 +1143,68 @@ void Contents_SMB::DeliverSMB(int len, const u_char* data)
|
||||||
// Check the 4-byte header.
|
// Check the 4-byte header.
|
||||||
if ( strncmp((const char*) data, "\xffSMB", 4) )
|
if ( strncmp((const char*) data, "\xffSMB", 4) )
|
||||||
{
|
{
|
||||||
Conn()->Weird(fmt("SMB-over-TCP header error: %02x%02x%02x%02x, \\x%02x%c%c%c",
|
Conn()->Weird(fmt("SMB-over-TCP header error: %02x %05x, >>\\x%02x%c%c%c<<",
|
||||||
dshdr[0], dshdr[1], dshdr[2], dshdr[3],
|
//dshdr[0], dshdr[1], dshdr[2], dshdr[3],
|
||||||
|
msg_type, msg_len,
|
||||||
data[0], data[1], data[2], data[3]));
|
data[0], data[1], data[2], data[3]));
|
||||||
SetSkip(1);
|
SetSkip(1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
smb_session->Deliver(IsOrig(), len, data);
|
smb_session->Deliver(IsOrig(), len, data, first_time, last_time);
|
||||||
|
|
||||||
buf_n = 0;
|
|
||||||
msg_len = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Contents_SMB::DeliverStream(int len, const u_char* data, bool orig)
|
void Contents_SMB::DeliverStream(int len, const u_char* data, bool orig)
|
||||||
{
|
{
|
||||||
TCP_SupportAnalyzer::DeliverStream(len, data, orig);
|
TCP_SupportAnalyzer::DeliverStream(len, data, orig);
|
||||||
|
if (Skipping())
|
||||||
|
return;
|
||||||
|
|
||||||
|
last_time = network_time;
|
||||||
while ( len > 0 )
|
while ( len > 0 )
|
||||||
{
|
{
|
||||||
if ( ! msg_len )
|
switch (state) {
|
||||||
|
case WAIT_FOR_HDR:
|
||||||
{
|
{
|
||||||
// Get the SMB-over-TCP header (4 bytes).
|
if (first_time < 1e-3)
|
||||||
while ( buf_n < 4 && len > 0 )
|
first_time = network_time;
|
||||||
|
bool got_hdr = hdr_buf.ConsumeChunk(data, len);
|
||||||
|
if (got_hdr)
|
||||||
{
|
{
|
||||||
dshdr[buf_n] = *data;
|
// We have the 4 bytes header now
|
||||||
++buf_n; ++data; --len;
|
const u_char *dummy = hdr_buf.GetBuf();
|
||||||
}
|
if (dummy[1] > 1)
|
||||||
|
Conn()->Weird(fmt("NetBIOS session flags > 1: %d", dummy[1]));
|
||||||
if ( buf_n < 4 )
|
msg_len = 0;
|
||||||
return;
|
msg_type = dummy[0];
|
||||||
|
for ( int i =1; i < 4; i++)
|
||||||
buf_n = 0;
|
msg_len = ( msg_len << 8) + dummy[i];
|
||||||
for ( int i = 1; i < 4; ++i )
|
msg_buf.Init(SMB_MAX_LEN, msg_len);
|
||||||
msg_len = ( msg_len << 8 ) + dshdr[i];
|
state = WAIT_FOR_DATA;
|
||||||
|
|
||||||
if ( dshdr[0] != 0 )
|
|
||||||
{
|
|
||||||
// Netbios header indicates this is NOT
|
|
||||||
// a session message ...
|
|
||||||
// 0x81 = session request
|
|
||||||
// 0x82 = positive response
|
|
||||||
// 0x83 = neg response
|
|
||||||
// 0x84 = retarget(?)
|
|
||||||
// 0x85 = keepalive
|
|
||||||
// Maybe we should just generate a Netbios
|
|
||||||
// event and die?
|
|
||||||
Conn()->Weird("SMB checked Netbios type and found != 0");
|
|
||||||
SetSkip(1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ( msg_len <= 4 )
|
|
||||||
{
|
|
||||||
Conn()->Weird("SMB message length error");
|
|
||||||
SetSkip(1);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
if ( buf_n == 0 && msg_len <= len )
|
case WAIT_FOR_DATA:
|
||||||
{
|
{
|
||||||
// The fast lane:
|
bool got_all_data = msg_buf.ConsumeChunk(data, len);
|
||||||
// Keep msg_len -- it will be changed in DeliverSMB
|
if (got_all_data)
|
||||||
int mlen = msg_len;
|
|
||||||
DeliverSMB(msg_len, data);
|
|
||||||
len -= mlen;
|
|
||||||
data += mlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ( buf_len < msg_len )
|
|
||||||
InitMsgBuf();
|
|
||||||
|
|
||||||
while ( buf_n < msg_len && len > 0 )
|
|
||||||
{
|
{
|
||||||
msg_buf[buf_n] = *data;
|
const u_char *dummy_p = msg_buf.GetBuf();
|
||||||
++buf_n;
|
int dummy_len = (int) msg_buf.GetFill();
|
||||||
++data;
|
if (msg_type == 0x00 && dummy_len >= 4)
|
||||||
--len;
|
DeliverSMB(dummy_len, dummy_p);
|
||||||
|
else if (msg_type == 0x00)
|
||||||
|
Conn()->Weird(fmt("SMB too short: len=%d", msg_len));
|
||||||
|
else
|
||||||
|
Conn()->Weird(fmt("SMB other msg type: %x", msg_type));
|
||||||
|
state = WAIT_FOR_HDR;
|
||||||
|
first_time = 0.0;
|
||||||
|
hdr_buf.Init(4,4);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( buf_n < msg_len )
|
|
||||||
return;
|
|
||||||
|
|
||||||
DeliverSMB(msg_len, msg_buf);
|
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
|
} // end switch
|
||||||
|
} // end while
|
||||||
}
|
}
|
||||||
|
|
||||||
SMB_Analyzer::SMB_Analyzer(Connection* conn)
|
SMB_Analyzer::SMB_Analyzer(Connection* conn)
|
||||||
|
|
28
src/SMB.h
28
src/SMB.h
|
@ -9,6 +9,7 @@
|
||||||
// Reference: http://www.snia.org/tech_activities/CIFS/CIFS-TR-1p00_FINAL.pdf
|
// Reference: http://www.snia.org/tech_activities/CIFS/CIFS-TR-1p00_FINAL.pdf
|
||||||
|
|
||||||
#include "TCP.h"
|
#include "TCP.h"
|
||||||
|
#include "RPC.h"
|
||||||
#include "DCE_RPC.h"
|
#include "DCE_RPC.h"
|
||||||
#include "smb_pac.h"
|
#include "smb_pac.h"
|
||||||
|
|
||||||
|
@ -44,7 +45,8 @@ public:
|
||||||
SMB_Session(Analyzer* analyzer);
|
SMB_Session(Analyzer* analyzer);
|
||||||
~SMB_Session();
|
~SMB_Session();
|
||||||
|
|
||||||
void Deliver(int is_orig, int len, const u_char* msg);
|
void Deliver(int is_orig, int len, const u_char* msg,
|
||||||
|
double first_time, double last_time);
|
||||||
|
|
||||||
static bool any_smb_event()
|
static bool any_smb_event()
|
||||||
{
|
{
|
||||||
|
@ -170,6 +172,8 @@ protected:
|
||||||
bool smb_pipe_prot;
|
bool smb_pipe_prot;
|
||||||
StringVal* transaction_name;
|
StringVal* transaction_name;
|
||||||
binpac::SMB::SMB_andx* andx_[2];
|
binpac::SMB::SMB_andx* andx_[2];
|
||||||
|
double first_time;
|
||||||
|
double last_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Contents_SMB : public TCP_SupportAnalyzer {
|
class Contents_SMB : public TCP_SupportAnalyzer {
|
||||||
|
@ -180,16 +184,21 @@ public:
|
||||||
virtual void DeliverStream(int len, const u_char* data, bool orig);
|
virtual void DeliverStream(int len, const u_char* data, bool orig);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void InitMsgBuf();
|
typedef enum {
|
||||||
|
WAIT_FOR_HDR,
|
||||||
|
WAIT_FOR_DATA
|
||||||
|
} state_t;
|
||||||
void DeliverSMB(int len, const u_char* data);
|
void DeliverSMB(int len, const u_char* data);
|
||||||
|
|
||||||
SMB_Session* smb_session;
|
SMB_Session* smb_session;
|
||||||
u_char dshdr[4];
|
|
||||||
u_char* msg_buf;
|
RPC_Reasm_Buffer hdr_buf; // Reassemlbes the NetBIOS length and glue
|
||||||
|
RPC_Reasm_Buffer msg_buf; // Reassembles the SMB message.
|
||||||
int msg_len;
|
int msg_len;
|
||||||
int buf_n; // number of bytes in msg_buf
|
int msg_type;
|
||||||
int buf_len; // size off msg_buf
|
double first_time; // timestamp of first packet of current message
|
||||||
|
double last_time; // timestamp of last pakcet of current message
|
||||||
|
state_t state;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SMB_Analyzer : public TCP_ApplicationAnalyzer {
|
class SMB_Analyzer : public TCP_ApplicationAnalyzer {
|
||||||
|
@ -202,8 +211,9 @@ public:
|
||||||
|
|
||||||
static bool Available()
|
static bool Available()
|
||||||
{
|
{
|
||||||
return SMB_Session::any_smb_event() ||
|
return true;
|
||||||
DCE_RPC_Session::any_dce_rpc_event();
|
//return SMB_Session::any_smb_event() ||
|
||||||
|
// DCE_RPC_Session::any_dce_rpc_event();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -221,8 +221,10 @@ event smb_com_transaction2%(c: connection, hdr: smb_hdr, trans: smb_trans, data:
|
||||||
event smb_com_trans_mailslot%(c: connection, hdr: smb_hdr, trans: smb_trans, data: smb_trans_data, is_orig: bool%);
|
event smb_com_trans_mailslot%(c: connection, hdr: smb_hdr, trans: smb_trans, data: smb_trans_data, is_orig: bool%);
|
||||||
event smb_com_trans_rap%(c: connection, hdr: smb_hdr, trans: smb_trans, data: smb_trans_data, is_orig: bool%);
|
event smb_com_trans_rap%(c: connection, hdr: smb_hdr, trans: smb_trans, data: smb_trans_data, is_orig: bool%);
|
||||||
event smb_com_trans_pipe%(c: connection, hdr: smb_hdr, trans: smb_trans, data: smb_trans_data, is_orig: bool%);
|
event smb_com_trans_pipe%(c: connection, hdr: smb_hdr, trans: smb_trans, data: smb_trans_data, is_orig: bool%);
|
||||||
event smb_com_read_andx%(c: connection, hdr: smb_hdr, data: string%);
|
event smb_com_read_andx%(c: connection, hdr: smb_hdr, fid: count%);
|
||||||
event smb_com_write_andx%(c: connection, hdr: smb_hdr, data: string%);
|
event smb_com_read_andx_response%(c: connection, hdr: smb_hdr, len: count%);
|
||||||
|
event smb_com_write_andx%(c: connection, hdr: smb_hdr, fid: count, len: count%);
|
||||||
|
event smb_com_write_andx_response%(c: connection, hdr: smb_hdr%);
|
||||||
event smb_get_dfs_referral%(c: connection, hdr: smb_hdr, max_referral_level: count, file_name: string%);
|
event smb_get_dfs_referral%(c: connection, hdr: smb_hdr, max_referral_level: count, file_name: string%);
|
||||||
event smb_com_negotiate%(c: connection, hdr: smb_hdr%);
|
event smb_com_negotiate%(c: connection, hdr: smb_hdr%);
|
||||||
event smb_com_negotiate_response%(c: connection, hdr: smb_hdr, dialect_index: count%);
|
event smb_com_negotiate_response%(c: connection, hdr: smb_hdr, dialect_index: count%);
|
||||||
|
|
|
@ -337,12 +337,12 @@ type SMB_read_andx_response = record {
|
||||||
reserved2 : uint16[4];
|
reserved2 : uint16[4];
|
||||||
byte_count : uint16;
|
byte_count : uint16;
|
||||||
pad : padding[padding_length];
|
pad : padding[padding_length];
|
||||||
data : bytestring &length = data_length;
|
#data : bytestring &length = data_length;
|
||||||
# Chris: the length here is causing problems - could we be having
|
# Chris: the length here is causing problems - could we be having
|
||||||
# issues with the packet format or is the data_length just not
|
# issues with the packet format or is the data_length just not
|
||||||
# right. The problem is that the padding isn't always filled right,
|
# right. The problem is that the padding isn't always filled right,
|
||||||
# espeically when its not the first command in the packet.
|
# espeically when its not the first command in the packet.
|
||||||
#data : bytestring &restofdata;
|
data : bytestring &restofdata;
|
||||||
} &let {
|
} &let {
|
||||||
data_length = data_len_high * 0x10000 + data_len;
|
data_length = data_len_high * 0x10000 + data_len;
|
||||||
padding_length = byte_count - data_length;
|
padding_length = byte_count - data_length;
|
||||||
|
@ -353,7 +353,7 @@ type SMB_write_andx = record {
|
||||||
andx : SMB_andx;
|
andx : SMB_andx;
|
||||||
fid : uint16;
|
fid : uint16;
|
||||||
offset : uint32;
|
offset : uint32;
|
||||||
reserved : uint32;
|
timeout : uint32;
|
||||||
write_mode : uint16;
|
write_mode : uint16;
|
||||||
remaining : uint16;
|
remaining : uint16;
|
||||||
data_len_high : uint16;
|
data_len_high : uint16;
|
||||||
|
@ -362,7 +362,8 @@ type SMB_write_andx = record {
|
||||||
rest_words : uint8[word_count * 2 - offsetof(rest_words) + 1];
|
rest_words : uint8[word_count * 2 - offsetof(rest_words) + 1];
|
||||||
byte_count : uint16;
|
byte_count : uint16;
|
||||||
pad : padding to data_offset - smb_header_length;
|
pad : padding to data_offset - smb_header_length;
|
||||||
data : bytestring &length = data_length;
|
#data : bytestring &length = data_length;
|
||||||
|
data : bytestring &restofdata;
|
||||||
} &let {
|
} &let {
|
||||||
data_length = data_len_high * 0x10000 + data_len;
|
data_length = data_len_high * 0x10000 + data_len;
|
||||||
} &byteorder = littleendian;
|
} &byteorder = littleendian;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue