mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Fixes to DCE_RPC analysis
- Previously there was an (incorrect) assumption that a TCP conneciton would only ever have one DCE_RPC binding. That assumption was incorrect and with named pipes over SMB there can be multiple concurrent DCE_RPC bindings. This commit fixes that assumption by dynamically creating a new DCE_RPC analyzer whenever a new, unknown binding is created. - There is a crash fix in how string handling in the bind_ack message was done. - Named pipe handling over SMB1 is still not working quite right and problems will show up with multiplexed DCE_RPC bindings.
This commit is contained in:
parent
caa28bc3c5
commit
003b32f904
13 changed files with 171 additions and 59 deletions
|
@ -36,9 +36,15 @@ type State: record {
|
||||||
named_pipe : string &optional;
|
named_pipe : string &optional;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type Stuff: record {
|
||||||
|
info: Info;
|
||||||
|
state: State;
|
||||||
|
};
|
||||||
|
|
||||||
redef record connection += {
|
redef record connection += {
|
||||||
dce_rpc: Info &optional;
|
dce_rpc: Info &optional;
|
||||||
dce_rpc_state: State &default=State();
|
dce_rpc_state: State &optional;
|
||||||
|
dce_rpc_state_x: table[count] of Stuff &optional;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ports = { 135/tcp };
|
const ports = { 135/tcp };
|
||||||
|
@ -50,14 +56,10 @@ event bro_init() &priority=5
|
||||||
Analyzer::register_for_ports(Analyzer::ANALYZER_DCE_RPC, ports);
|
Analyzer::register_for_ports(Analyzer::ANALYZER_DCE_RPC, ports);
|
||||||
}
|
}
|
||||||
|
|
||||||
function set_session(c: connection)
|
function set_state(c: connection, state_x: Stuff)
|
||||||
{
|
{
|
||||||
if ( ! c?$dce_rpc )
|
c$dce_rpc = state_x$info;
|
||||||
{
|
c$dce_rpc_state = state_x$state;
|
||||||
c$dce_rpc = [$ts=network_time(),
|
|
||||||
$id=c$id,
|
|
||||||
$uid=c$uid];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( c$dce_rpc_state?$uuid )
|
if ( c$dce_rpc_state?$uuid )
|
||||||
c$dce_rpc$endpoint = uuid_endpoint_map[c$dce_rpc_state$uuid];
|
c$dce_rpc$endpoint = uuid_endpoint_map[c$dce_rpc_state$uuid];
|
||||||
|
@ -65,9 +67,25 @@ function set_session(c: connection)
|
||||||
c$dce_rpc$named_pipe = c$dce_rpc_state$named_pipe;
|
c$dce_rpc$named_pipe = c$dce_rpc_state$named_pipe;
|
||||||
}
|
}
|
||||||
|
|
||||||
event dce_rpc_bind(c: connection, uuid: string, ver_major: count, ver_minor: count) &priority=5
|
function set_session(c: connection, fid: count)
|
||||||
{
|
{
|
||||||
set_session(c);
|
if ( ! c?$dce_rpc_state_x )
|
||||||
|
{
|
||||||
|
c$dce_rpc_state_x = table();
|
||||||
|
}
|
||||||
|
if ( fid !in c$dce_rpc_state_x )
|
||||||
|
{
|
||||||
|
local info = Info($ts=network_time(),$id=c$id,$uid=c$uid);
|
||||||
|
c$dce_rpc_state_x[fid] = Stuff($info=info, $state=State());
|
||||||
|
}
|
||||||
|
|
||||||
|
local state_x = c$dce_rpc_state_x[fid];
|
||||||
|
set_state(c, state_x);
|
||||||
|
}
|
||||||
|
|
||||||
|
event dce_rpc_bind(c: connection, fid: count, uuid: string, ver_major: count, ver_minor: count) &priority=5
|
||||||
|
{
|
||||||
|
set_session(c, fid);
|
||||||
|
|
||||||
local uuid_str = uuid_to_string(uuid);
|
local uuid_str = uuid_to_string(uuid);
|
||||||
if ( uuid_str in ignored_uuids )
|
if ( uuid_str in ignored_uuids )
|
||||||
|
@ -77,9 +95,9 @@ event dce_rpc_bind(c: connection, uuid: string, ver_major: count, ver_minor: cou
|
||||||
c$dce_rpc$endpoint = uuid_endpoint_map[uuid_str];
|
c$dce_rpc$endpoint = uuid_endpoint_map[uuid_str];
|
||||||
}
|
}
|
||||||
|
|
||||||
event dce_rpc_bind_ack(c: connection, sec_addr: string) &priority=5
|
event dce_rpc_bind_ack(c: connection, fid: count, sec_addr: string) &priority=5
|
||||||
{
|
{
|
||||||
set_session(c);
|
set_session(c, fid);
|
||||||
|
|
||||||
if ( sec_addr != "" )
|
if ( sec_addr != "" )
|
||||||
{
|
{
|
||||||
|
@ -88,19 +106,19 @@ event dce_rpc_bind_ack(c: connection, sec_addr: string) &priority=5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
event dce_rpc_request(c: connection, opnum: count, stub_len: count) &priority=5
|
event dce_rpc_request(c: connection, fid: count, opnum: count, stub_len: count) &priority=5
|
||||||
{
|
{
|
||||||
set_session(c);
|
set_session(c, fid);
|
||||||
|
|
||||||
if ( c?$dce_rpc )
|
if ( c?$dce_rpc )
|
||||||
{
|
{
|
||||||
c$dce_rpc$ts = network_time();
|
c$dce_rpc$ts = network_time();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
event dce_rpc_response(c: connection, opnum: count, stub_len: count) &priority=5
|
event dce_rpc_response(c: connection, fid: count, opnum: count, stub_len: count) &priority=5
|
||||||
{
|
{
|
||||||
set_session(c);
|
set_session(c, fid);
|
||||||
|
|
||||||
if ( c?$dce_rpc && c$dce_rpc?$endpoint )
|
if ( c?$dce_rpc && c$dce_rpc?$endpoint )
|
||||||
{
|
{
|
||||||
|
@ -110,11 +128,11 @@ event dce_rpc_response(c: connection, opnum: count, stub_len: count) &priority=5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
event dce_rpc_response(c: connection, opnum: count, stub_len: count) &priority=-5
|
event dce_rpc_response(c: connection, fid: count, opnum: count, stub_len: count) &priority=-5
|
||||||
{
|
{
|
||||||
if ( c?$dce_rpc )
|
if ( c?$dce_rpc )
|
||||||
{
|
{
|
||||||
# If there is not endpoint, there isn't much reason to log.
|
# If there is not an endpoint, there isn't much reason to log.
|
||||||
# This can happen if the request isn't seen.
|
# This can happen if the request isn't seen.
|
||||||
if ( c$dce_rpc?$endpoint )
|
if ( c$dce_rpc?$endpoint )
|
||||||
Log::write(LOG, c$dce_rpc);
|
Log::write(LOG, c$dce_rpc);
|
||||||
|
@ -128,4 +146,11 @@ event connection_state_remove(c: connection)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
# TODO: Go through any remaining dce_rpc requests that haven't been processed with replies.
|
# TODO: Go through any remaining dce_rpc requests that haven't been processed with replies.
|
||||||
|
for ( i in c$dce_rpc_state_x )
|
||||||
|
{
|
||||||
|
local x = c$dce_rpc_state_x[i];
|
||||||
|
set_state(c, x);
|
||||||
|
if ( c$dce_rpc?$endpoint )
|
||||||
|
Log::write(LOG, c$dce_rpc);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -185,6 +185,9 @@ public:
|
||||||
virtual void Undelivered(uint64 seq, int len, bool orig);
|
virtual void Undelivered(uint64 seq, int len, bool orig);
|
||||||
virtual void EndpointEOF(bool is_orig);
|
virtual void EndpointEOF(bool is_orig);
|
||||||
|
|
||||||
|
bool SetFileID(uint64 fid_in)
|
||||||
|
{ interp->set_file_id(fid_in); return true; }
|
||||||
|
|
||||||
static analyzer::Analyzer* Instantiate(Connection* conn)
|
static analyzer::Analyzer* Instantiate(Connection* conn)
|
||||||
{ return new DCE_RPC_Analyzer(conn); }
|
{ return new DCE_RPC_Analyzer(conn); }
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,19 @@
|
||||||
refine connection DCE_RPC_Conn += {
|
refine connection DCE_RPC_Conn += {
|
||||||
%member{
|
%member{
|
||||||
map<uint16, uint16> cont_id_opnum_map;
|
map<uint16, uint16> cont_id_opnum_map;
|
||||||
|
uint64 fid;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
%init{
|
||||||
|
fid=0;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function set_file_id(fid_in: uint64): bool
|
||||||
|
%{
|
||||||
|
fid = fid_in;
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
function get_cont_id_opnum_map(cont_id: uint16): uint16
|
function get_cont_id_opnum_map(cont_id: uint16): uint16
|
||||||
%{
|
%{
|
||||||
return cont_id_opnum_map[cont_id];
|
return cont_id_opnum_map[cont_id];
|
||||||
|
@ -30,6 +41,7 @@ refine connection DCE_RPC_Conn += {
|
||||||
BifEvent::generate_dce_rpc_message(bro_analyzer(),
|
BifEvent::generate_dce_rpc_message(bro_analyzer(),
|
||||||
bro_analyzer()->Conn(),
|
bro_analyzer()->Conn(),
|
||||||
${header.is_orig},
|
${header.is_orig},
|
||||||
|
fid,
|
||||||
${header.PTYPE},
|
${header.PTYPE},
|
||||||
new EnumVal(${header.PTYPE}, BifType::Enum::DCE_RPC::PType));
|
new EnumVal(${header.PTYPE}, BifType::Enum::DCE_RPC::PType));
|
||||||
}
|
}
|
||||||
|
@ -52,6 +64,7 @@ refine connection DCE_RPC_Conn += {
|
||||||
// Queue the event
|
// Queue the event
|
||||||
BifEvent::generate_dce_rpc_bind(bro_analyzer(),
|
BifEvent::generate_dce_rpc_bind(bro_analyzer(),
|
||||||
bro_analyzer()->Conn(),
|
bro_analyzer()->Conn(),
|
||||||
|
fid,
|
||||||
bytestring_to_val(${uuid}),
|
bytestring_to_val(${uuid}),
|
||||||
${ver_major},
|
${ver_major},
|
||||||
${ver_minor});
|
${ver_minor});
|
||||||
|
@ -67,13 +80,19 @@ refine connection DCE_RPC_Conn += {
|
||||||
{
|
{
|
||||||
StringVal *sec_addr;
|
StringVal *sec_addr;
|
||||||
// Remove the null from the end of the string if it's there.
|
// Remove the null from the end of the string if it's there.
|
||||||
if ( *(${bind.sec_addr}.begin() + ${bind.sec_addr}.length()) == 0 )
|
if ( ${bind.sec_addr}.length() > 0 &&
|
||||||
|
*(${bind.sec_addr}.begin() + ${bind.sec_addr}.length()) == 0 )
|
||||||
|
{
|
||||||
sec_addr = new StringVal(${bind.sec_addr}.length()-1, (const char*) ${bind.sec_addr}.begin());
|
sec_addr = new StringVal(${bind.sec_addr}.length()-1, (const char*) ${bind.sec_addr}.begin());
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
sec_addr = new StringVal(${bind.sec_addr}.length(), (const char*) ${bind.sec_addr}.begin());
|
sec_addr = new StringVal(${bind.sec_addr}.length(), (const char*) ${bind.sec_addr}.begin());
|
||||||
|
}
|
||||||
|
|
||||||
BifEvent::generate_dce_rpc_bind_ack(bro_analyzer(),
|
BifEvent::generate_dce_rpc_bind_ack(bro_analyzer(),
|
||||||
bro_analyzer()->Conn(),
|
bro_analyzer()->Conn(),
|
||||||
|
fid,
|
||||||
sec_addr);
|
sec_addr);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -85,6 +104,7 @@ refine connection DCE_RPC_Conn += {
|
||||||
{
|
{
|
||||||
BifEvent::generate_dce_rpc_request(bro_analyzer(),
|
BifEvent::generate_dce_rpc_request(bro_analyzer(),
|
||||||
bro_analyzer()->Conn(),
|
bro_analyzer()->Conn(),
|
||||||
|
fid,
|
||||||
${req.opnum},
|
${req.opnum},
|
||||||
${req.stub}.length());
|
${req.stub}.length());
|
||||||
}
|
}
|
||||||
|
@ -100,6 +120,7 @@ refine connection DCE_RPC_Conn += {
|
||||||
{
|
{
|
||||||
BifEvent::generate_dce_rpc_response(bro_analyzer(),
|
BifEvent::generate_dce_rpc_response(bro_analyzer(),
|
||||||
bro_analyzer()->Conn(),
|
bro_analyzer()->Conn(),
|
||||||
|
fid,
|
||||||
get_cont_id_opnum_map(${resp.context_id}),
|
get_cont_id_opnum_map(${resp.context_id}),
|
||||||
${resp.stub}.length());
|
${resp.stub}.length());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
## .. bro:see:: dce_rpc_bind dce_rpc_bind_ack dce_rpc_request dce_rpc_response
|
## .. bro:see:: dce_rpc_bind dce_rpc_bind_ack dce_rpc_request dce_rpc_response
|
||||||
event dce_rpc_message%(c: connection, is_orig: bool, ptype_id: count, ptype: DCE_RPC::PType%);
|
event dce_rpc_message%(c: connection, is_orig: bool, fid: count, ptype_id: count, ptype: DCE_RPC::PType%);
|
||||||
|
|
||||||
## .. bro:see:: dce_rpc_message dce_rpc_bind_ack dce_rpc_request dce_rpc_response
|
## .. bro:see:: dce_rpc_message dce_rpc_bind_ack dce_rpc_request dce_rpc_response
|
||||||
event dce_rpc_bind%(c: connection, uuid: string, ver_major: count, ver_minor: count%);
|
event dce_rpc_bind%(c: connection, fid: count, uuid: string, ver_major: count, ver_minor: count%);
|
||||||
|
|
||||||
## .. bro:see:: dce_rpc_message dce_rpc_bind dce_rpc_request dce_rpc_response
|
## .. bro:see:: dce_rpc_message dce_rpc_bind dce_rpc_request dce_rpc_response
|
||||||
event dce_rpc_bind_ack%(c: connection, sec_addr: string%);
|
event dce_rpc_bind_ack%(c: connection, fid: count, sec_addr: string%);
|
||||||
|
|
||||||
## .. bro:see:: dce_rpc_message dce_rpc_bind dce_rpc_bind_ack dce_rpc_response
|
## .. bro:see:: dce_rpc_message dce_rpc_bind dce_rpc_bind_ack dce_rpc_response
|
||||||
event dce_rpc_request%(c: connection, opnum: count, stub_len: count%);
|
event dce_rpc_request%(c: connection, fid: count, opnum: count, stub_len: count%);
|
||||||
|
|
||||||
## .. bro:see:: dce_rpc_message dce_rpc_bind dce_rpc_bind_ack dce_rpc_request
|
## .. bro:see:: dce_rpc_message dce_rpc_bind dce_rpc_bind_ack dce_rpc_request
|
||||||
event dce_rpc_response%(c: connection, opnum: count, stub_len: count%);
|
event dce_rpc_response%(c: connection, fid: count, opnum: count, stub_len: count%);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,17 @@
|
||||||
|
|
||||||
refine connection SMB_Conn += {
|
refine connection SMB_Conn += {
|
||||||
|
%member{
|
||||||
|
analyzer::Analyzer *gssapi;
|
||||||
|
%}
|
||||||
|
|
||||||
|
%init{
|
||||||
|
gssapi = analyzer_mgr->InstantiateAnalyzer("GSSAPI", bro_analyzer->Conn());
|
||||||
|
%}
|
||||||
|
|
||||||
|
%cleanup{
|
||||||
|
if ( gssapi )
|
||||||
|
delete gssapi;
|
||||||
|
%}
|
||||||
|
|
||||||
function forward_gssapi(data: bytestring, is_orig: bool): bool
|
function forward_gssapi(data: bytestring, is_orig: bool): bool
|
||||||
%{
|
%{
|
||||||
|
|
|
@ -1,9 +1,23 @@
|
||||||
|
%extern{
|
||||||
|
#include "../dce-rpc/DCE_RPC.h"
|
||||||
|
%}
|
||||||
|
|
||||||
refine connection SMB_Conn += {
|
refine connection SMB_Conn += {
|
||||||
%member{
|
%member{
|
||||||
map<uint16,bool> tree_is_pipe_map;
|
map<uint16,bool> tree_is_pipe_map;
|
||||||
|
map<uint64,analyzer::dce_rpc::DCE_RPC_Analyzer*> fid_to_analyzer_map;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
%cleanup{
|
||||||
|
// Iterate all of the analyzers and destroy them.
|
||||||
|
for ( auto kv : fid_to_analyzer_map )
|
||||||
|
{
|
||||||
|
if ( kv.second )
|
||||||
|
delete kv.second;
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
|
||||||
|
|
||||||
function get_tree_is_pipe(tree_id: uint16): bool
|
function get_tree_is_pipe(tree_id: uint16): bool
|
||||||
%{
|
%{
|
||||||
if ( tree_is_pipe_map.count(tree_id) > 0 )
|
if ( tree_is_pipe_map.count(tree_id) > 0 )
|
||||||
|
@ -18,10 +32,22 @@ refine connection SMB_Conn += {
|
||||||
return true;
|
return true;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
function forward_dce_rpc(pipe_data: bytestring, is_orig: bool): bool
|
function forward_dce_rpc(pipe_data: bytestring, fid: uint64, is_orig: bool): bool
|
||||||
%{
|
%{
|
||||||
if ( dcerpc )
|
analyzer::dce_rpc::DCE_RPC_Analyzer *pipe_dcerpc;
|
||||||
dcerpc->DeliverStream(${pipe_data}.length(), ${pipe_data}.begin(), is_orig);
|
if ( fid_to_analyzer_map.count(fid) == 0 )
|
||||||
|
{
|
||||||
|
pipe_dcerpc = (analyzer::dce_rpc::DCE_RPC_Analyzer *)analyzer_mgr->InstantiateAnalyzer("DCE_RPC", bro_analyzer()->Conn());
|
||||||
|
pipe_dcerpc->SetFileID(fid);
|
||||||
|
fid_to_analyzer_map[fid] = pipe_dcerpc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pipe_dcerpc = fid_to_analyzer_map.at(fid);
|
||||||
|
}
|
||||||
|
|
||||||
|
pipe_dcerpc->DeliverStream(${pipe_data}.length(), ${pipe_data}.begin(), is_orig);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
%}
|
%}
|
||||||
};
|
};
|
|
@ -135,22 +135,3 @@ type SMB_Protocol_Identifier(is_orig: bool, msg_len: uint32) = record {
|
||||||
flow SMB_Flow(is_orig: bool) {
|
flow SMB_Flow(is_orig: bool) {
|
||||||
flowunit = SMB_TCP(is_orig) withcontext(connection, this);
|
flowunit = SMB_TCP(is_orig) withcontext(connection, this);
|
||||||
};
|
};
|
||||||
|
|
||||||
refine connection SMB_Conn += {
|
|
||||||
%member{
|
|
||||||
analyzer::Analyzer *dcerpc;
|
|
||||||
analyzer::Analyzer *gssapi;
|
|
||||||
%}
|
|
||||||
|
|
||||||
%init{
|
|
||||||
dcerpc = analyzer_mgr->InstantiateAnalyzer("DCE_RPC", bro_analyzer->Conn());
|
|
||||||
gssapi = analyzer_mgr->InstantiateAnalyzer("GSSAPI", bro_analyzer->Conn());
|
|
||||||
%}
|
|
||||||
|
|
||||||
%cleanup{
|
|
||||||
if ( dcerpc )
|
|
||||||
delete dcerpc;
|
|
||||||
if ( gssapi )
|
|
||||||
delete gssapi;
|
|
||||||
%}
|
|
||||||
};
|
|
||||||
|
|
|
@ -83,7 +83,7 @@ type SMB1_read_andx_response(header: SMB_Header) = record {
|
||||||
data : bytestring &length=data_len;
|
data : bytestring &length=data_len;
|
||||||
} &let {
|
} &let {
|
||||||
is_pipe : bool = $context.connection.get_tree_is_pipe(header.tid);
|
is_pipe : bool = $context.connection.get_tree_is_pipe(header.tid);
|
||||||
pipe_proc : bool = $context.connection.forward_dce_rpc(data, false) &if(is_pipe);
|
pipe_proc : bool = $context.connection.forward_dce_rpc(data, 0, false) &if(is_pipe);
|
||||||
|
|
||||||
padding_len : uint8 = (header.unicode == 1) ? 1 : 0;
|
padding_len : uint8 = (header.unicode == 1) ? 1 : 0;
|
||||||
data_len : uint32 = (data_len_high << 16) + data_len_low;
|
data_len : uint32 = (data_len_high << 16) + data_len_low;
|
||||||
|
|
|
@ -70,7 +70,7 @@ type SMB1_transaction_data(header: SMB_Header, is_orig: bool, count: uint16, sub
|
||||||
SMB_UNKNOWN -> unknown : bytestring &restofdata &transient;
|
SMB_UNKNOWN -> unknown : bytestring &restofdata &transient;
|
||||||
default -> data : bytestring &restofdata &transient;
|
default -> data : bytestring &restofdata &transient;
|
||||||
} &let {
|
} &let {
|
||||||
pipe_proc : bool = $context.connection.forward_dce_rpc(pipe_data, is_orig) &if(trans_type == SMB_PIPE);
|
pipe_proc : bool = $context.connection.forward_dce_rpc(pipe_data, 0, is_orig) &if(trans_type == SMB_PIPE);
|
||||||
};
|
};
|
||||||
|
|
||||||
type SMB1_transaction_setup(header: SMB_Header) = record {
|
type SMB1_transaction_setup(header: SMB_Header) = record {
|
||||||
|
|
|
@ -55,7 +55,7 @@ type SMB1_write_andx_request(header: SMB_Header) = record {
|
||||||
data : bytestring &length=data_len;
|
data : bytestring &length=data_len;
|
||||||
} &let {
|
} &let {
|
||||||
is_pipe : bool = $context.connection.get_tree_is_pipe(header.tid);
|
is_pipe : bool = $context.connection.get_tree_is_pipe(header.tid);
|
||||||
pipe_proc : bool = $context.connection.forward_dce_rpc(data, true) &if(is_pipe);
|
pipe_proc : bool = $context.connection.forward_dce_rpc(data, 0, true) &if(is_pipe);
|
||||||
|
|
||||||
data_len : uint32 = (data_len_high << 16) + data_len_low;
|
data_len : uint32 = (data_len_high << 16) + data_len_low;
|
||||||
offset_high : uint32 = (word_count == 0x0E) ? offset_high_tmp : 0;
|
offset_high : uint32 = (word_count == 0x0E) ? offset_high_tmp : 0;
|
||||||
|
|
|
@ -1,4 +1,25 @@
|
||||||
refine connection SMB_Conn += {
|
refine connection SMB_Conn += {
|
||||||
|
%member{
|
||||||
|
std::map<uint64,uint64> smb2_ioctl_fids;
|
||||||
|
%}
|
||||||
|
|
||||||
|
function get_ioctl_fid(message_id: uint64): uint64
|
||||||
|
%{
|
||||||
|
if ( smb2_ioctl_fids.count(message_id) == 0 )
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint64 fid = smb2_ioctl_fids[message_id];
|
||||||
|
smb2_ioctl_fids.erase(message_id);
|
||||||
|
return fid;
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
|
||||||
|
function proc_smb2_ioctl_request(val: SMB2_ioctl_request) : bool
|
||||||
|
%{
|
||||||
|
smb2_ioctl_fids[${val.header.message_id}] = ${val.file_id.persistent} + ${val.file_id._volatile};
|
||||||
|
return true;
|
||||||
|
%}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,7 +43,9 @@ type SMB2_ioctl_request(header: SMB2_Header) = record {
|
||||||
} &let {
|
} &let {
|
||||||
# We only handle FSCTL_PIPE_TRANSCEIVE messages right now.
|
# We only handle FSCTL_PIPE_TRANSCEIVE messages right now.
|
||||||
is_pipe: bool = (ctl_code == 0x0011C017);
|
is_pipe: bool = (ctl_code == 0x0011C017);
|
||||||
pipe_proc : bool = $context.connection.forward_dce_rpc(input_buffer, true) &if(is_pipe);
|
fid: uint64 = file_id.persistent + file_id._volatile;
|
||||||
|
pipe_proc : bool = $context.connection.forward_dce_rpc(input_buffer, fid, true) &if(is_pipe);
|
||||||
|
proc : bool = $context.connection.proc_smb2_ioctl_request(this);
|
||||||
};
|
};
|
||||||
|
|
||||||
type SMB2_ioctl_response(header: SMB2_Header) = record {
|
type SMB2_ioctl_response(header: SMB2_Header) = record {
|
||||||
|
@ -42,6 +65,7 @@ type SMB2_ioctl_response(header: SMB2_Header) = record {
|
||||||
output_buffer : bytestring &length=output_count;
|
output_buffer : bytestring &length=output_count;
|
||||||
} &let {
|
} &let {
|
||||||
# We only handle FSCTL_PIPE_TRANSCEIVE messages right now.
|
# We only handle FSCTL_PIPE_TRANSCEIVE messages right now.
|
||||||
is_pipe: bool = (ctl_code == 0x0011C017);
|
is_pipe : bool = (ctl_code == 0x0011C017);
|
||||||
pipe_proc : bool = $context.connection.forward_dce_rpc(output_buffer, false) &if(is_pipe);
|
fid : uint64 = $context.connection.get_ioctl_fid(header.message_id);
|
||||||
|
pipe_proc : bool = $context.connection.forward_dce_rpc(output_buffer, fid, false) &if(is_pipe);
|
||||||
};
|
};
|
|
@ -4,8 +4,21 @@ refine connection SMB_Conn += {
|
||||||
// Track read offsets to provide correct
|
// Track read offsets to provide correct
|
||||||
// offsets for file manager.
|
// offsets for file manager.
|
||||||
std::map<uint16,uint64> smb2_read_offsets;
|
std::map<uint16,uint64> smb2_read_offsets;
|
||||||
|
std::map<uint64,uint64> smb2_read_fids;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
function get_file_id(message_id: uint64): uint64
|
||||||
|
%{
|
||||||
|
if ( smb2_read_fids.count(message_id) == 0 )
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint64 fid = smb2_read_fids[message_id];
|
||||||
|
smb2_read_fids.erase(message_id);
|
||||||
|
return fid;
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
|
||||||
function proc_smb2_read_request(h: SMB2_Header, val: SMB2_read_request) : bool
|
function proc_smb2_read_request(h: SMB2_Header, val: SMB2_read_request) : bool
|
||||||
%{
|
%{
|
||||||
if ( smb2_read_request )
|
if ( smb2_read_request )
|
||||||
|
@ -19,22 +32,28 @@ refine connection SMB_Conn += {
|
||||||
}
|
}
|
||||||
|
|
||||||
smb2_read_offsets[${h.message_id}] = ${val.offset};
|
smb2_read_offsets[${h.message_id}] = ${val.offset};
|
||||||
|
smb2_read_fids[${h.message_id}] = ${val.file_id.persistent} + ${val.file_id._volatile};
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
function proc_smb2_read_response(h: SMB2_Header, val: SMB2_read_response) : bool
|
function proc_smb2_read_response(h: SMB2_Header, val: SMB2_read_response) : bool
|
||||||
%{
|
%{
|
||||||
|
uint64 offset = smb2_read_offsets[${h.message_id}];
|
||||||
|
smb2_read_offsets.erase(${h.message_id});
|
||||||
|
|
||||||
if ( ! ${val.is_pipe} && ${val.data_len} > 0 )
|
if ( ! ${val.is_pipe} && ${val.data_len} > 0 )
|
||||||
{
|
{
|
||||||
uint64 offset = smb2_read_offsets[${h.message_id}];
|
|
||||||
smb2_read_offsets.erase(${h.message_id});
|
|
||||||
|
|
||||||
file_mgr->DataIn(${val.data}.begin(), ${val.data_len}, offset,
|
file_mgr->DataIn(${val.data}.begin(), ${val.data_len}, offset,
|
||||||
bro_analyzer()->GetAnalyzerTag(),
|
bro_analyzer()->GetAnalyzerTag(),
|
||||||
bro_analyzer()->Conn(), h->is_orig());
|
bro_analyzer()->Conn(), h->is_orig());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ( ${val.is_pipe} )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
@ -69,8 +88,9 @@ type SMB2_read_response(header: SMB2_Header) = record {
|
||||||
pad : padding to data_offset - header.head_length;
|
pad : padding to data_offset - header.head_length;
|
||||||
data : bytestring &length=data_len;
|
data : bytestring &length=data_len;
|
||||||
} &let {
|
} &let {
|
||||||
is_pipe : bool = $context.connection.get_tree_is_pipe(header.tree_id);
|
is_pipe : bool = $context.connection.get_tree_is_pipe(header.tree_id);
|
||||||
pipe_proc : bool = $context.connection.forward_dce_rpc(data, false) &if(is_pipe);
|
fid : uint64 = $context.connection.get_file_id(header.message_id);
|
||||||
|
pipe_proc : bool = $context.connection.forward_dce_rpc(data, fid, false) &if(is_pipe);
|
||||||
|
|
||||||
proc: bool = $context.connection.proc_smb2_read_response(header, this);
|
proc: bool = $context.connection.proc_smb2_read_response(header, this);
|
||||||
};
|
};
|
||||||
|
|
|
@ -46,7 +46,7 @@ type SMB2_write_request(header: SMB2_Header) = record {
|
||||||
data : bytestring &length=data_len;
|
data : bytestring &length=data_len;
|
||||||
} &let {
|
} &let {
|
||||||
is_pipe: bool = $context.connection.get_tree_is_pipe(header.tree_id);
|
is_pipe: bool = $context.connection.get_tree_is_pipe(header.tree_id);
|
||||||
pipe_proc : bool = $context.connection.forward_dce_rpc(data, true) &if(is_pipe);
|
pipe_proc : bool = $context.connection.forward_dce_rpc(data, file_id.persistent+file_id._volatile, true) &if(is_pipe);
|
||||||
|
|
||||||
proc : bool = $context.connection.proc_smb2_write_request(header, this);
|
proc : bool = $context.connection.proc_smb2_write_request(header, this);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue