Redo DCE/RPC code.

This commit is contained in:
Vlad Grigorescu 2014-10-09 21:06:38 -04:00
parent c4eb7e2377
commit 9a73033b19
16 changed files with 1036 additions and 79 deletions

View file

@ -26,6 +26,96 @@ export {
"\\wkssvc", "\\wkssvc",
}; };
## The UUIDs used by the various RPC endpoints
const rpc_uuids: table[string] of string = {
["4b324fc8-1670-01d3-1278-5a47bf6ee188"] = "Server Service",
["6bffd098-a112-3610-9833-46c3f87e345a"] = "Workstation Service",
} &redef &default=function(i: string):string { return fmt("unknown-uuid-%s", i); };
## Server service sub commands
const srv_cmds: table[count] of string = {
[8] = "NetrConnectionEnum",
[9] = "NetrFileEnum",
[10] = "NetrFileGetInfo",
[11] = "NetrFileClose",
[12] = "NetrSessionEnum",
[13] = "NetrSessionDel",
[14] = "NetrShareAdd",
[15] = "NetrShareEnum",
[16] = "NetrShareGetInfo",
[17] = "NetrShareSetInfo",
[18] = "NetrShareDel",
[19] = "NetrShareDelSticky",
[20] = "NetrShareCheck",
[21] = "NetrServerGetInfo",
[22] = "NetrServerSetInfo",
[23] = "NetrServerDiskEnum",
[24] = "NetrServerStatisticsGet",
[25] = "NetrServerTransportAdd",
[26] = "NetrServerTransportEnum",
[27] = "NetrServerTransportDel",
[28] = "NetrRemoteTOD",
[30] = "NetprPathType",
[31] = "NetprPathCanonicalize",
[32] = "NetprPathCompare",
[33] = "NetprNameValidate",
[34] = "NetprNameCanonicalize",
[35] = "NetprNameCompare",
[36] = "NetrShareEnumSticky",
[37] = "NetrShareDelStart",
[38] = "NetrShareDelCommit",
[39] = "NetrGetFileSecurity",
[40] = "NetrSetFileSecurity",
[41] = "NetrServerTransportAddEx",
[43] = "NetrDfsGetVersion",
[44] = "NetrDfsCreateLocalPartition",
[45] = "NetrDfsDeleteLocalPartition",
[46] = "NetrDfsSetLocalVolumeState",
[48] = "NetrDfsCreateExitPoint",
[49] = "NetrDfsDeleteExitPoint",
[50] = "NetrDfsModifyPrefix",
[51] = "NetrDfsFixLocalVolume",
[52] = "NetrDfsManagerReportSiteInfo",
[53] = "NetrServerTransportDelEx",
[54] = "NetrServerAliasAdd",
[55] = "NetrServerAliasEnum",
[56] = "NetrServerAliasDel",
[57] = "NetrShareDelEx",
} &redef &default=function(i: count):string { return fmt("unknown-srv-command-%d", i); };
## Workstation service sub commands
const wksta_cmds: table[count] of string = {
[0] = "NetrWkstaGetInfo",
[1] = "NetrWkstaSetInfo",
[2] = "NetrWkstaUserEnum",
[5] = "NetrWkstaTransportEnum",
[6] = "NetrWkstaTransportAdd",
[7] = "NetrWkstaTransportDel",
[8] = "NetrUseAdd",
[9] = "NetrUseGetInfo",
[10] = "NetrUseDel",
[11] = "NetrUseEnum",
[13] = "NetrWorkstationStatisticsGet",
[20] = "NetrGetJoinInformation",
[22] = "NetrJoinDomain2",
[23] = "NetrUnjoinDomain2",
[24] = "NetrRenameMachineInDomain2",
[25] = "NetrValidateName2",
[26] = "NetrGetJoinableOUs2",
[27] = "NetrAddAlternateComputerName",
[28] = "NetrRemoveAlternateComputerName",
[29] = "NetrSetPrimaryComputerName",
[30] = "NetrEnumerateComputerNames",
} &redef &default=function(i: count):string { return fmt("unknown-wksta-command-%d", i); };
type rpc_cmd_table: table[count] of string;
## The subcommands for RPC endpoints
const rpc_sub_cmds: table[string] of rpc_cmd_table = {
["4b324fc8-1670-01d3-1278-5a47bf6ee188"] = srv_cmds,
["6bffd098-a112-3610-9833-46c3f87e345a"] = wksta_cmds,
} &redef &default=function(i: string):rpc_cmd_table { return table() &default=function(j: string):string { return fmt("unknown-uuid-%s", j); }; };
} }
module SMB1; module SMB1;

View file

@ -128,6 +128,8 @@ export {
tid_map : table[count] of TreeInfo &optional; tid_map : table[count] of TreeInfo &optional;
## User map to retrieve user name based on the user ID. ## User map to retrieve user name based on the user ID.
uid_map : table[count] of string &optional; uid_map : table[count] of string &optional;
## Pipe map to retrieve UUID based on the file ID of a pipe.
pipe_map : table[count] of string &optional;
}; };
redef record connection += { redef record connection += {
@ -139,6 +141,7 @@ export {
## Some commands shouldn't be logged by the smb1_message event ## Some commands shouldn't be logged by the smb1_message event
const deferred_logging_cmds: set[string] = { const deferred_logging_cmds: set[string] = {
"NEGOTIATE", "NEGOTIATE",
"READ_ANDX",
"SESSION_SETUP_ANDX", "SESSION_SETUP_ANDX",
"TREE_CONNECT_ANDX", "TREE_CONNECT_ANDX",
}; };
@ -152,10 +155,13 @@ export {
redef record FileInfo += { redef record FileInfo += {
## ID referencing this file. ## ID referencing this file.
fid : count &optional; fid : count &optional;
## Maintain a reference to the file record. ## Maintain a reference to the file record.
f : fa_file &optional; f : fa_file &optional;
## UUID referencing this file if DCE/RPC
uuid: string &optional;
}; };
const ports = { 139/tcp, 445/tcp }; const ports = { 139/tcp, 445/tcp };

View file

@ -13,6 +13,7 @@ event smb1_message(c: connection, hdr: SMB1::Header, is_orig: bool) &priority=5
state$fid_map = table(); state$fid_map = table();
state$tid_map = table(); state$tid_map = table();
state$uid_map = table(); state$uid_map = table();
state$pipe_map = table();
state$pending_cmds = table(); state$pending_cmds = table();
c$smb_state = state; c$smb_state = state;
} }
@ -180,21 +181,25 @@ event smb1_read_andx_request(c: connection, hdr: SMB1::Header, file_id: count, o
{ {
if ( c$smb_state$current_tree?$path && !c$smb_state$current_file?$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; c$smb_state$current_file$path = c$smb_state$current_tree$path;
# TODO - Why is this commented out? # TODO - Why is this commented out?
#write_file_log(c$smb_state$current_file); #write_file_log(c$smb_state$current_file);
} }
#event smb1_read_andx_response(c: connection, hdr: SMB1::Header, data_len: count) &priority=5 event smb1_read_andx_response(c: connection, hdr: SMB1::Header, data_len: count) &priority=5
# { {
# # TODO - determine what to do here if ( c$smb_state$current_cmd$status !in SMB::ignored_command_statuses )
# } {
Log::write(SMB::CMD_LOG, c$smb_state$current_cmd);
}
}
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_state, file_id); SMB::set_current_file(c$smb_state, file_id);
c$smb_state$current_file$action = SMB::FILE_WRITE; c$smb_state$current_file$action = SMB::FILE_WRITE;
c$smb_state$current_cmd$argument = c$smb_state$current_file$name; if ( !c$smb_state$current_cmd?$argument )
c$smb_state$current_cmd$argument = c$smb_state$current_file$name;
} }
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
@ -312,4 +317,37 @@ event smb_ntlm_authenticate(c: connection, hdr: SMB1::Header, request: SMB::NTLM
event smb1_transaction_request(c: connection, hdr: SMB1::Header, name: string, sub_cmd: count) event smb1_transaction_request(c: connection, hdr: SMB1::Header, name: string, sub_cmd: count)
{ {
c$smb_state$current_cmd$sub_command = SMB1::trans_sub_commands[sub_cmd]; c$smb_state$current_cmd$sub_command = SMB1::trans_sub_commands[sub_cmd];
} }
event smb1_write_andx_request(c: connection, hdr: SMB1::Header, file_id: count, offset: count, data_len: count)
{
c$smb_state$pipe_map[file_id] = c$smb_state$current_file$uuid;
}
event smb_pipe_bind_ack_response(c: connection, hdr: SMB1::Header)
{
c$smb_state$current_cmd$sub_command = "RPC_BIND_ACK";
c$smb_state$current_cmd$argument = SMB::rpc_uuids[c$smb_state$current_file$uuid];
}
event smb_pipe_bind_request(c: connection, hdr: SMB1::Header, uuid: string, version: string)
{
c$smb_state$current_cmd$sub_command = "RPC_BIND";
c$smb_state$current_file$uuid = uuid;
c$smb_state$current_cmd$argument = fmt("%s v%s", SMB::rpc_uuids[uuid], version);
}
event smb_pipe_request(c: connection, hdr: SMB1::Header, op_num: count)
{
c$smb_state$current_cmd$argument = fmt("%s: %s", SMB::rpc_uuids[c$smb_state$current_file$uuid],
SMB::rpc_sub_cmds[c$smb_state$current_file$uuid][op_num]);
}
#event smb1_transaction_setup(c: connection, hdr: SMB1::Header, op_code: count, file_id: count)
# {
# local uuid = SMB::rpc_uuids[c$smb_state$pipe_map[file_id]];
# if ( uuid in SMB::rpc_uuids )
# {
# print fmt("smb1_transaction_setup %s", SMB::rap_cmds[op_code]);
# }
# }

View file

@ -0,0 +1,588 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include "config.h"
#include <stdlib.h>
#include <string>
#include <map>
using namespace std;
#include "DCE_RPC.h"
#include "Sessions.h"
#include "analyzer/Manager.h"
#include "events.bif.h"
using namespace analyzer::dce_rpc;
#define xbyte(b, n) (((const u_char*) (b))[n])
#define extract_uint16(little_endian, bytes) \
((little_endian) ? \
uint16(xbyte(bytes, 0)) | ((uint16(xbyte(bytes, 1))) << 8) : \
uint16(xbyte(bytes, 1)) | ((uint16(xbyte(bytes, 0))) << 8))
static int uuid_index[] = {
3, 2, 1, 0,
5, 4, 7, 6,
8, 9, 10, 11,
12, 13, 14, 15
};
const char* analyzer::dce_rpc::uuid_to_string(const u_char* uuid_data)
{
static char s[1024];
char* sp = s;
for ( int i = 0; i < 16; ++i )
{
if ( i == 4 || i == 6 || i == 8 || i == 10 )
sp += snprintf(sp, s + sizeof(s) - sp, "-");
int j = uuid_index[i];
sp += snprintf(sp, s + sizeof(s) - sp, "%02x", uuid_data[j]);
}
return s;
}
UUID::UUID()
{
memset(data, 0, 16);
s = uuid_to_string(data);
}
UUID::UUID(const u_char d[16])
{
memcpy(data, d, 16);
s = uuid_to_string(data);
}
UUID::UUID(const binpac::bytestring& uuid)
{
if ( uuid.length() != 16 )
reporter->InternalError("UUID length error");
memcpy(data, uuid.begin(), 16);
s = uuid_to_string(data);
}
UUID::UUID(const char* str)
{
s = string(str);
const char* sp = str;
int i;
for ( i = 0; i < 16; ++i )
{
if ( *sp == '-' )
++sp;
if ( ! *sp || ! *(sp+1) )
break;
data[uuid_index[i]] =
(u_char) (decode_hex(*sp) * 16 + decode_hex(*(sp+1)));
}
if ( i != 16 )
reporter->InternalError("invalid UUID string: %s", str);
}
typedef map<UUID, BifEnum::dce_rpc_if_id> uuid_map_t;
static uuid_map_t& well_known_uuid_map()
{
static uuid_map_t the_map;
static bool initialized = false;
if ( initialized )
return the_map;
using namespace BifEnum;
the_map[UUID("e1af8308-5d1f-11c9-91a4-08002b14a0fa")] = DCE_RPC_epmapper;
the_map[UUID("afa8bd80-7d8a-11c9-bef4-08002b102989")] = DCE_RPC_mgmt;
// It's said that the following interfaces are merely aliases.
the_map[UUID("12345778-1234-abcd-ef00-0123456789ab")] = DCE_RPC_lsarpc;
the_map[UUID("12345678-1234-abcd-ef00-01234567cffb")] = DCE_RPC_netlogon;
the_map[UUID("12345778-1234-abcd-ef00-0123456789ac")] = DCE_RPC_samr;
// The next group of aliases.
the_map[UUID("4b324fc8-1670-01d3-1278-5a47bf6ee188")] = DCE_RPC_srvsvc;
the_map[UUID("12345678-1234-abcd-ef00-0123456789ab")] = DCE_RPC_spoolss;
the_map[UUID("45f52c28-7f9f-101a-b52b-08002b2efabe")] = DCE_RPC_winspipe;
the_map[UUID("6bffd098-a112-3610-9833-46c3f87e345a")] = DCE_RPC_wkssvc;
// DRS - NT directory replication service.
the_map[UUID("e3514235-4b06-11d1-ab04-00c04fc2dcd2")] = DCE_RPC_drs;
// "The IOXIDResolver RPC interface (formerly known as
// IObjectExporter) is remotely used to reach the local object
// resolver (OR)."
the_map[UUID("99fcfec4-5260-101b-bbcb-00aa0021347a")] = DCE_RPC_oxid;
the_map[UUID("3919286a-b10c-11d0-9ba8-00c04fd92ef5")] = DCE_RPC_lsa_ds;
the_map[UUID("000001a0-0000-0000-c000-000000000046")] = DCE_RPC_ISCMActivator;
initialized = true;
return the_map;
}
// Used to remember mapped DCE/RPC endpoints and parse the follow-up
// connections as DCE/RPC sessions.
map<dce_rpc_endpoint_addr, UUID> dce_rpc_endpoints;
static bool is_mapped_dce_rpc_endpoint(const dce_rpc_endpoint_addr& addr)
{
return dce_rpc_endpoints.find(addr) != dce_rpc_endpoints.end();
}
bool is_mapped_dce_rpc_endpoint(const ConnID* id, TransportProto proto)
{
if ( id->dst_addr.GetFamily() == IPv6 )
// TODO: Does the protocol support v6 addresses? #773
return false;
dce_rpc_endpoint_addr addr;
addr.addr = id->dst_addr;
addr.port = ntohs(id->dst_port);
addr.proto = proto;
return is_mapped_dce_rpc_endpoint(addr);
}
static void add_dce_rpc_endpoint(const dce_rpc_endpoint_addr& addr,
const UUID& uuid)
{
DEBUG_MSG("Adding endpoint %s @ %s\n",
uuid.to_string(), addr.to_string().c_str());
dce_rpc_endpoints[addr] = uuid;
// FIXME: Once we can pass the cookie to the analyzer, we can get rid
// of the dce_rpc_endpoints table.
// FIXME: Don't hard-code the timeout.
analyzer_mgr->ScheduleAnalyzer(IPAddr(), addr.addr, addr.port, addr.proto,
"DCE_RPC", 5 * 60);
}
DCE_RPC_Header::DCE_RPC_Header(analyzer::Analyzer* a, const u_char* b)
{
analyzer = a;
bytes = b;
// This checks whether it's both the first fragment *and*
// the last fragment.
if ( (bytes[3] & 0x3) != 0x3 )
{
fragmented = 1;
Weird("Fragmented DCE/RPC message");
}
else
fragmented = 0;
ptype = (BifEnum::dce_rpc_ptype) bytes[2];
frag_len = extract_uint16(LittleEndian(), bytes + 8);
}
DCE_RPC_Session::DCE_RPC_Session(analyzer::Analyzer* a)
: analyzer(a),
if_uuid("00000000-0000-0000-0000-000000000000"),
if_id(BifEnum::DCE_RPC_unknown_if)
{
opnum = -1;
}
bool DCE_RPC_Session::LooksLikeRPC(int len, const u_char* msg)
{
// if ( ! is_IPC )
// return false;
try
{
binpac::DCE_RPC_Simple::DCE_RPC_Header h;
h.Parse(msg, msg + len);
if ( h.rpc_vers() == 5 && h.rpc_vers_minor() == 0 )
{
if ( h.frag_length() == len )
return true;
else
{
DEBUG_MSG("length mismatch: %d != %d\n",
h.frag_length(), len);
return false;
}
}
}
catch ( const binpac::Exception& )
{
// do nothing
}
return false;
}
void DCE_RPC_Session::DeliverPDU(int is_orig, int len, const u_char* data)
{
if ( dce_rpc_message )
{
val_list* vl = new val_list;
vl->append(analyzer->BuildConnVal());
vl->append(new Val(is_orig, TYPE_BOOL));
vl->append(new EnumVal(data[2], BifType::Enum::dce_rpc_ptype));
vl->append(new StringVal(len, (const char*) data));
analyzer->ConnectionEvent(dce_rpc_message, vl);
}
try
{
// TODO: handle incremental input
binpac::DCE_RPC_Simple::DCE_RPC_PDU pdu;
pdu.Parse(data, data + len);
switch ( pdu.header()->PTYPE() ) {
case binpac::DCE_RPC_Simple::DCE_RPC_BIND:
case binpac::DCE_RPC_Simple::DCE_RPC_ALTER_CONTEXT:
DeliverBind(&pdu);
break;
case binpac::DCE_RPC_Simple::DCE_RPC_REQUEST:
DeliverRequest(&pdu);
break;
case binpac::DCE_RPC_Simple::DCE_RPC_RESPONSE:
DeliverResponse(&pdu);
break;
}
}
catch ( const binpac::Exception& e )
{
analyzer->Weird(e.msg().c_str());
}
}
void DCE_RPC_Session::DeliverBind(const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu)
{
binpac::DCE_RPC_Simple::DCE_RPC_Bind* bind = pdu->body()->bind();
for ( int i = 0; i < bind->p_context_elem()->n_context_elem(); ++i )
{
binpac::DCE_RPC_Simple::p_cont_elem_t* elem =
(*bind->p_context_elem()->p_cont_elem())[i];
if_uuid = UUID(elem->abstract_syntax()->if_uuid().begin());
uuid_map_t::const_iterator uuid_it =
well_known_uuid_map().find(if_uuid);
if ( uuid_it == well_known_uuid_map().end() )
{
#ifdef DEBUG
// conn->Weird(fmt("Unknown DCE_RPC interface %s",
// if_uuid.to_string()));
#endif
if_id = BifEnum::DCE_RPC_unknown_if;
}
else
if_id = uuid_it->second;
if ( dce_rpc_bind )
{
val_list* vl = new val_list;
vl->append(analyzer->BuildConnVal());
vl->append(new StringVal(if_uuid.to_string()));
// vl->append(new EnumVal(if_id, BifType::Enum::dce_rpc_if_id));
analyzer->ConnectionEvent(dce_rpc_bind, vl);
}
}
}
void DCE_RPC_Session::DeliverRequest(const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu)
{
binpac::DCE_RPC_Simple::DCE_RPC_Request* req = pdu->body()->request();
opnum = req->opnum();
if ( dce_rpc_request )
{
val_list* vl = new val_list;
vl->append(analyzer->BuildConnVal());
vl->append(new Val(opnum, TYPE_COUNT));
vl->append(new StringVal(req->stub().length(),
(const char*) req->stub().begin()));
analyzer->ConnectionEvent(dce_rpc_request, vl);
}
switch ( if_id ) {
case BifEnum::DCE_RPC_epmapper:
DeliverEpmapperRequest(pdu, req);
break;
default:
break;
}
}
void DCE_RPC_Session::DeliverResponse(const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu)
{
binpac::DCE_RPC_Simple::DCE_RPC_Response* resp = pdu->body()->response();
if ( dce_rpc_response )
{
val_list* vl = new val_list;
vl->append(analyzer->BuildConnVal());
vl->append(new Val(opnum, TYPE_COUNT));
vl->append(new StringVal(resp->stub().length(),
(const char*) resp->stub().begin()));
analyzer->ConnectionEvent(dce_rpc_response, vl);
}
switch ( if_id ) {
case BifEnum::DCE_RPC_epmapper:
DeliverEpmapperResponse(pdu, resp);
break;
default:
break;
}
}
void DCE_RPC_Session::DeliverEpmapperRequest(
const binpac::DCE_RPC_Simple::DCE_RPC_PDU* /* pdu */,
const binpac::DCE_RPC_Simple::DCE_RPC_Request* /* req */)
{
// DEBUG_MSG("Epmapper request opnum = %d\n", req->opnum());
// ### TODO(rpang): generate an event on epmapper request
}
void DCE_RPC_Session::DeliverEpmapperResponse(
const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu,
const binpac::DCE_RPC_Simple::DCE_RPC_Response* resp)
{
// DEBUG_MSG("Epmapper request opnum = %d\n", req->opnum());
switch ( opnum ) {
case 3: // Map
DeliverEpmapperMapResponse(pdu, resp);
break;
}
}
void DCE_RPC_Session::DeliverEpmapperMapResponse(
const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu,
const binpac::DCE_RPC_Simple::DCE_RPC_Response* resp)
{
try
{
binpac::DCE_RPC_Simple::epmapper_map_resp epm_resp;
epm_resp.Parse(resp->stub().begin(), resp->stub().end(),
pdu->byteorder());
for ( unsigned int twr_i = 0;
twr_i < epm_resp.towers()->actual_count(); ++twr_i )
{
binpac::DCE_RPC_Simple::epm_tower* twr =
(*epm_resp.towers()->towers())[twr_i]->tower();
mapped.addr = dce_rpc_endpoint_addr();
mapped.uuid = UUID();
for ( int floor_i = 0; floor_i < twr->num_floors();
++floor_i )
{
binpac::DCE_RPC_Simple::epm_floor* floor =
(*twr->floors())[floor_i];
switch ( floor->protocol() ) {
case binpac::DCE_RPC_Simple::EPM_PROTOCOL_UUID:
if ( floor_i == 0 )
mapped.uuid = UUID(floor->lhs()->data()->uuid()->if_uuid());
break;
case binpac::DCE_RPC_Simple::EPM_PROTOCOL_TCP:
mapped.addr.port =
floor->rhs()->data()->tcp();
mapped.addr.proto = TRANSPORT_TCP;
break;
case binpac::DCE_RPC_Simple::EPM_PROTOCOL_UDP:
mapped.addr.port =
floor->rhs()->data()->udp();
mapped.addr.proto = TRANSPORT_UDP;
break;
case binpac::DCE_RPC_Simple::EPM_PROTOCOL_IP:
uint32 hostip = floor->rhs()->data()->ip();
mapped.addr.addr = IPAddr(IPv4, &hostip, IPAddr::Host);
break;
}
}
if ( mapped.addr.is_valid_addr() )
add_dce_rpc_endpoint(mapped.addr, mapped.uuid);
if ( epm_map_response )
{
val_list* vl = new val_list;
vl->append(analyzer->BuildConnVal());
vl->append(new StringVal(mapped.uuid.to_string()));
vl->append(new PortVal(mapped.addr.port, mapped.addr.proto));
vl->append(new AddrVal(mapped.addr.addr));
analyzer->ConnectionEvent(epm_map_response, vl);
}
}
}
catch ( const binpac::Exception& e )
{
analyzer->Weird(e.msg().c_str());
}
}
Contents_DCE_RPC_Analyzer::Contents_DCE_RPC_Analyzer(Connection* conn,
bool orig, DCE_RPC_Session* arg_session, bool speculative)
: tcp::TCP_SupportAnalyzer("CONTENTS_DCE_RPC", conn, orig)
{
session = arg_session;
msg_buf = 0;
buf_len = 0;
speculation = speculative ? 0 : 1;
InitState();
}
void Contents_DCE_RPC_Analyzer::InitState()
{
// Allocate space for header.
if ( ! msg_buf )
{
buf_len = DCE_RPC_HEADER_LENGTH;
msg_buf = new u_char[buf_len];
}
buf_n = 0;
msg_len = 0;
hdr = 0;
}
Contents_DCE_RPC_Analyzer::~Contents_DCE_RPC_Analyzer()
{
delete [] msg_buf;
delete hdr;
}
void Contents_DCE_RPC_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
{
tcp::TCP_SupportAnalyzer::DeliverStream(len, data, orig);
tcp::TCP_Analyzer* tcp =
static_cast<tcp::TCP_ApplicationAnalyzer*>(Parent())->TCP();
if ( tcp->HadGap(orig) || tcp->IsPartial() )
return;
if ( speculation == 0 ) // undecided
{
if ( ! DCE_RPC_Session::LooksLikeRPC(len, data) )
speculation = -1;
else
speculation = 1;
}
if ( speculation < 0 )
return;
ASSERT(buf_len >= DCE_RPC_HEADER_LENGTH);
while ( len > 0 )
{
if ( buf_n < DCE_RPC_HEADER_LENGTH )
{
while ( buf_n < DCE_RPC_HEADER_LENGTH && len > 0 )
{
msg_buf[buf_n] = *data;
++buf_n; ++data; --len;
}
if ( buf_n < DCE_RPC_HEADER_LENGTH )
break;
else
{
if ( ! ParseHeader() )
return;
}
}
while ( buf_n < msg_len && len > 0 )
{
msg_buf[buf_n] = *data;
++buf_n; ++data; --len;
}
if ( buf_n < msg_len )
break;
else
{
if ( msg_len > 0 )
DeliverPDU(msg_len, msg_buf);
// Reset for next message
InitState();
}
}
}
void Contents_DCE_RPC_Analyzer::DeliverPDU(int len, const u_char* data)
{
session->DeliverPDU(IsOrig(), len, data);
}
bool Contents_DCE_RPC_Analyzer::ParseHeader()
{
delete hdr;
hdr = 0;
if ( msg_buf[0] != 5 ) // DCE/RPC version
{
Conn()->Weird("DCE/RPC_version_error (non-DCE/RPC?)");
Conn()->SetSkip(1);
msg_len = 0;
return false;
}
hdr = new DCE_RPC_Header(this, msg_buf);
msg_len = hdr->FragLen();
if ( msg_len > buf_len )
{
u_char* new_msg_buf = new u_char[msg_len];
memcpy(new_msg_buf, msg_buf, buf_n);
delete [] msg_buf;
buf_len = msg_len;
msg_buf = new_msg_buf;
hdr->SetBytes(new_msg_buf);
}
return true;
}
DCE_RPC_Analyzer::DCE_RPC_Analyzer(Connection* conn, bool arg_speculative)
: tcp::TCP_ApplicationAnalyzer("DCE_RPC", conn)
{
session = new DCE_RPC_Session(this);
speculative = arg_speculative;
AddSupportAnalyzer(new Contents_DCE_RPC_Analyzer(conn, true, session,
speculative));
AddSupportAnalyzer(new Contents_DCE_RPC_Analyzer(conn, false, session,
speculative));
}
DCE_RPC_Analyzer::~DCE_RPC_Analyzer()
{
delete session;
}

View file

@ -0,0 +1,191 @@
// See the file "COPYING" in the main distribution directory for copyright.
#ifndef ANALYZER_PROTOCOL_DCE_RPC_DCE_RPC_H
#define ANALYZER_PROTOCOL_DCE_RPC_DCE_RPC_H
// NOTE: This is a somewhat crude analyzer for DCE/RPC (used on Microsoft
// Windows systems) and shouldn't be considered as stable.
#include "NetVar.h"
#include "analyzer/protocol/tcp/TCP.h"
#include "analyzer/protocol/dce-rpc/events.bif.h"
#include "IPAddr.h"
#include "dce_rpc_simple_pac.h"
namespace analyzer { namespace dce_rpc {
class UUID {
public:
UUID();
UUID(const u_char data[16]);
UUID(const binpac::bytestring &uuid);
UUID(const char* s);
const char* to_string() const { return s.c_str(); }
const string& str() const { return s; }
bool operator==(const UUID& u) const
{ return s == u.str(); }
bool operator<(const UUID& u) const
{ return s < u.str(); }
protected:
u_char data[16];
string s;
};
const char* uuid_to_string(const u_char* uuid_data);
struct dce_rpc_endpoint_addr {
// All fields are in host byteorder.
IPAddr addr;
u_short port;
TransportProto proto;
dce_rpc_endpoint_addr()
{
addr = IPAddr();
port = 0;
proto = TRANSPORT_UNKNOWN;
}
bool is_valid_addr() const
{ return addr != IPAddr() && port != 0 && proto != TRANSPORT_UNKNOWN; }
bool operator<(dce_rpc_endpoint_addr const &e) const
{
if ( addr != e.addr )
return addr < e.addr;
if ( proto != e.proto )
return proto < e.proto;
if ( port != e.port )
return port < e.port;
return false;
}
string to_string() const
{
static char buf[128];
snprintf(buf, sizeof(buf), "%s/%d/%s",
addr.AsString().c_str(), port,
proto == TRANSPORT_TCP ? "tcp" :
(proto == TRANSPORT_UDP ? "udp" : "?"));
return string(buf);
}
};
/*
enum DCE_RPC_PTYPE {
DCE_RPC_REQUEST, DCE_RPC_PING, DCE_RPC_RESPONSE, DCE_RPC_FAULT,
DCE_RPC_WORKING, DCE_RPC_NOCALL, DCE_RPC_REJECT, DCE_RPC_ACK,
DCE_RPC_CL_CANCEL, DCE_RPC_FACK, DCE_RPC_CANCEL_ACK, DCE_RPC_BIND,
DCE_RPC_BIND_ACK, DCE_RPC_BIND_NAK, DCE_RPC_ALTER_CONTEXT,
DCE_RPC_ALTER_CONTEXT_RESP, DCE_RPC_SHUTDOWN, DCE_RPC_CO_CANCEL,
DCE_RPC_ORPHANED,
};
*/
#define DCE_RPC_HEADER_LENGTH 16
class DCE_RPC_Header {
public:
DCE_RPC_Header(analyzer::Analyzer* a, const u_char* bytes);
BifEnum::dce_rpc_ptype PTYPE() const { return ptype; }
int FragLen() const { return frag_len; }
int LittleEndian() const { return bytes[4] >> 4; }
bool Fragmented() const { return fragmented; }
void Weird(const char* msg) { analyzer->Weird(msg); }
void SetBytes(const u_char* b) { bytes = b; }
protected:
analyzer::Analyzer* analyzer;
const u_char* bytes;
BifEnum::dce_rpc_ptype ptype;
int frag_len;
bool fragmented;
};
// Create a general DCE_RPC_Session class so that it can be used in
// case the RPC conversation is tunneled through other connections,
// e.g. through an SMB session.
class DCE_RPC_Session {
public:
DCE_RPC_Session(analyzer::Analyzer* a);
virtual ~DCE_RPC_Session() {}
virtual void DeliverPDU(int is_orig, int len, const u_char* data);
static bool LooksLikeRPC(int len, const u_char* msg);
static bool any_dce_rpc_event()
{ return dce_rpc_message || dce_rpc_bind || dce_rpc_request; }
protected:
void DeliverBind(const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu);
void DeliverRequest(const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu);
void DeliverResponse(const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu);
void DeliverEpmapperRequest(
const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu,
const binpac::DCE_RPC_Simple::DCE_RPC_Request* req);
void DeliverEpmapperResponse(
const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu,
const binpac::DCE_RPC_Simple::DCE_RPC_Response* resp);
void DeliverEpmapperMapResponse(
const binpac::DCE_RPC_Simple::DCE_RPC_PDU* pdu,
const binpac::DCE_RPC_Simple::DCE_RPC_Response* resp);
analyzer::Analyzer* analyzer;
UUID if_uuid;
BifEnum::dce_rpc_if_id if_id;
int opnum;
struct {
dce_rpc_endpoint_addr addr;
UUID uuid;
} mapped;
};
class Contents_DCE_RPC_Analyzer : public tcp::TCP_SupportAnalyzer {
public:
Contents_DCE_RPC_Analyzer(Connection* conn, bool orig, DCE_RPC_Session* session,
bool speculative);
~Contents_DCE_RPC_Analyzer();
protected:
virtual void DeliverStream(int len, const u_char* data, bool orig);
virtual void DeliverPDU(int len, const u_char* data);
void InitState();
int speculation;
u_char* msg_buf;
int msg_len;
int buf_n; // number of bytes in msg_buf
int buf_len; // size off msg_buf
DCE_RPC_Header* hdr;
bool ParseHeader();
DCE_RPC_Session* session;
};
class DCE_RPC_Analyzer : public tcp::TCP_ApplicationAnalyzer {
public:
DCE_RPC_Analyzer(Connection* conn, bool speculative = false);
~DCE_RPC_Analyzer();
static analyzer::Analyzer* Instantiate(Connection* conn)
{ return new DCE_RPC_Analyzer(conn); }
protected:
DCE_RPC_Session* session;
bool speculative;
};
} } // namespace analyzer::*
#endif /* dce_rpc_h */

View file

@ -88,6 +88,16 @@ type DCE_RPC_Bind = record {
p_context_elem : p_cont_list_t; p_context_elem : p_cont_list_t;
}; };
type DCE_RPC_Bind_Ack = record {
max_xmit_frag : uint16;
max_recv_frag : uint16;
assoc_group_id : uint32;
sec_addr_length : uint16;
sec_addr : bytestring &length=sec_addr_length;
pad : padding align 4;
p_context_elem : p_cont_list_t;
};
type DCE_RPC_AlterContext = record { type DCE_RPC_AlterContext = record {
max_xmit_frag : uint16; max_xmit_frag : uint16;
max_recv_frag : uint16; max_recv_frag : uint16;
@ -115,6 +125,7 @@ type DCE_RPC_Response = record {
type DCE_RPC_Body(header: DCE_RPC_Header) = case header.PTYPE of { type DCE_RPC_Body(header: DCE_RPC_Header) = case header.PTYPE of {
DCE_RPC_BIND -> bind : DCE_RPC_Bind; DCE_RPC_BIND -> bind : DCE_RPC_Bind;
DCE_RPC_BIND_ACK -> bind_ack: DCE_RPC_Bind_Ack;
DCE_RPC_REQUEST -> request : DCE_RPC_Request; DCE_RPC_REQUEST -> request : DCE_RPC_Request;
DCE_RPC_RESPONSE -> response : DCE_RPC_Response; DCE_RPC_RESPONSE -> response : DCE_RPC_Response;
default -> other : bytestring &restofdata; default -> other : bytestring &restofdata;

View file

@ -3,44 +3,67 @@
%include dce_rpc-protocol.pac %include dce_rpc-protocol.pac
%extern{
#include "DCE_RPC.h"
%}
refine connection SMB_Conn += { refine connection SMB_Conn += {
function proc_smb_atsvc_job_add(val: AT_SVC_NetrJobAdd): bool
%{
if ( smb_atsvc_job_add )
{
BifEvent::generate_smb_atsvc_job_add(bro_analyzer(), bro_analyzer()->Conn(), smb_string2stringval(${val.server.string}), smb_string2stringval(${val.command.string}));
}
return true;
%}
function proc_smb_atsvc_job_id(val: AT_SVC_JobID): bool function get_tree_is_pipe(tree_id: uint16): bool
%{
if ( smb_atsvc_job_id )
{
BifEvent::generate_smb_atsvc_job_id(bro_analyzer(), bro_analyzer()->Conn(), ${val.id}, ${val.status});
}
return true;
%}
function determine_pipe_msg_type(hdr: DCE_RPC_Header, opnum: uint8): uint8
%{ %{
if ( !is_atsvc ) return 0; if ( tree_is_pipe_map.count(tree_id) == 0 )
if ( ${hdr.PTYPE} == 0 && ${opnum} == 0 ) return 1; return false;
if ( ${hdr.PTYPE} == 2 && ${opnum} == 0 ) return 2; return tree_is_pipe_map[tree_id];
return 0;
%} %}
function set_tree_is_pipe(tree_id: uint16, is_pipe: bool): bool
%{
tree_is_pipe_map[tree_id] = is_pipe;
return true;
%}
%member{
map<uint16,bool> tree_is_pipe_map;
%}
function proc_smb_pipe_message(val: SMB_Pipe_message, header: SMB_Header): bool
%{
switch ( ${val.rpc_header.PTYPE} ) {
case DCE_RPC_REQUEST:
if ( smb_pipe_request )
BifEvent::generate_smb_pipe_request(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header), \
${val.rpc_body.request.opnum});
break;
case DCE_RPC_RESPONSE:
if ( smb_pipe_response )
BifEvent::generate_smb_pipe_response(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header));
break;
case DCE_RPC_BIND_ACK:
if ( smb_pipe_bind_ack_response )
BifEvent::generate_smb_pipe_bind_ack_response(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header));
break;
case DCE_RPC_BIND:
if ( smb_pipe_bind_request )
// TODO - the version number needs to be calculated properly
BifEvent::generate_smb_pipe_bind_request(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header), \
new StringVal(analyzer::dce_rpc::uuid_to_string(bytestring_to_val(${val.rpc_body.bind.p_context_elem.p_cont_elem[0].abstract_syntax.if_uuid})->Bytes())), new StringVal(fmt("%d.0", ${val.rpc_body.bind.p_context_elem.p_cont_elem[0].abstract_syntax.if_version})));
break;
}
return true;
%}
}; };
type SMB_Pipe_message( unicode: bool, byte_count: uint16, sub_cmd: uint16 ) = record { type SMB_Pipe_message(header: SMB_Header, byte_count: uint16) = record {
rpc : DCE_RPC_Header; rpc_header : DCE_RPC_Header;
todo : padding[6]; # These fields are currently missing from DCE/RPC for some reason. rpc_body : DCE_RPC_Body(rpc_header);
opnum : uint8; # pipe_type: case $context.connection.determine_pipe_msg_type(rpc, opnum) of {
pipe_type: case $context.connection.determine_pipe_msg_type(rpc, opnum) of { # 1 -> atsvc_request : AT_SVC_Request(unicode, opnum);
1 -> atsvc_request : AT_SVC_Request(unicode, opnum); # 2 -> atsvc_reply : AT_SVC_Reply(unicode, opnum);
2 -> atsvc_reply : AT_SVC_Reply(unicode, opnum); # default -> unknown : bytestring &restofdata;
default -> unknown : bytestring &restofdata; # };
}; } &let {
proc: bool = $context.connection.proc_smb_pipe_message(this, header);
} &byteorder = littleendian; } &byteorder = littleendian;
type SMB_RAP_message( unicode: bool, byte_count: uint16 ) = record { type SMB_RAP_message( unicode: bool, byte_count: uint16 ) = record {
@ -77,8 +100,6 @@ type AT_SVC_NetrJobAdd(unicode: bool) = record {
flags : uint8; flags : uint8;
unknown2 : padding[2]; unknown2 : padding[2];
command : AT_SVC_String_Pointer(unicode); command : AT_SVC_String_Pointer(unicode);
} &let {
proc: bool = $context.connection.proc_smb_atsvc_job_add(this);
}; };
type AT_SVC_Reply(unicode: bool, opnum: uint16) = record { type AT_SVC_Reply(unicode: bool, opnum: uint16) = record {
@ -91,6 +112,4 @@ type AT_SVC_Reply(unicode: bool, opnum: uint16) = record {
type AT_SVC_JobID(unicode: bool) = record { type AT_SVC_JobID(unicode: bool) = record {
id: uint32; id: uint32;
status: uint32; status: uint32;
} &let {
proc: bool = $context.connection.proc_smb_atsvc_job_id(this);
}; };

View file

@ -379,8 +379,8 @@ type SMB_transaction_data(unicode: bool, count: uint16, sub_cmd: uint16,
SMB_MAILSLOT_BROWSE -> mailslot : SMB_MailSlot_message(unicode, count); SMB_MAILSLOT_BROWSE -> mailslot : SMB_MailSlot_message(unicode, count);
SMB_MAILSLOT_LANMAN -> lanman : SMB_MailSlot_message(unicode, count); SMB_MAILSLOT_LANMAN -> lanman : SMB_MailSlot_message(unicode, count);
SMB_RAP -> rap : SMB_Pipe_message(unicode, count, sub_cmd); SMB_RAP -> rap : SMB_Pipe_message(unicode, count);
SMB_PIPE -> pipe : SMB_Pipe_message(unicode, count, sub_cmd); SMB_PIPE -> pipe : SMB_Pipe_message(unicode, count);
SMB_UNKNOWN -> unknown : bytestring &restofdata; SMB_UNKNOWN -> unknown : bytestring &restofdata;
default -> data : bytestring &restofdata; default -> data : bytestring &restofdata;
@ -416,7 +416,7 @@ type SMB_transaction(trans_type: int, unicode: bool) = record {
determine_transaction_type( setup_count, name_string( this ))); determine_transaction_type( setup_count, name_string( this )));
} &let { } &let {
# does this work? # does this work?
sub_cmd : uint16 = setup_count ? setup[0] : 0; sub_cmd : uint16 = setup_count ? setup.op_code : 0;
} &byteorder = littleendian; } &byteorder = littleendian;

View file

@ -2,8 +2,6 @@ refine connection SMB_Conn += {
function proc_smb1_close_request(h: SMB_Header, val: SMB1_close_request): bool function proc_smb1_close_request(h: SMB_Header, val: SMB1_close_request): bool
%{ %{
is_atsvc = false;
if ( smb1_close_request ) if ( smb1_close_request )
BifEvent::generate_smb1_close_request(bro_analyzer(), BifEvent::generate_smb1_close_request(bro_analyzer(),
bro_analyzer()->Conn(), bro_analyzer()->Conn(),

View file

@ -1,23 +1,6 @@
refine connection SMB_Conn += { refine connection SMB_Conn += {
%member{
bool is_atsvc;
%}
%init{
is_atsvc = false;
%}
function isATSVC(): bool
%{
return is_atsvc;
%}
function proc_smb1_nt_create_andx_request(header: SMB_Header, val: SMB1_nt_create_andx_request): bool function proc_smb1_nt_create_andx_request(header: SMB_Header, val: SMB1_nt_create_andx_request): bool
%{ %{
if ( ${val.filename.u.s}->size() == 14 && ${val.filename.u.s[0]} == '\\' && ${val.filename.u.s[2]} == 'a' && ${val.filename.u.s[4]} == 't' && ${val.filename.u.s[6]} == 's' && ${val.filename.u.s[8]} == 'v' && ${val.filename.u.s[10]} == 'c' )
is_atsvc = true;
if ( smb1_nt_create_andx_request ) if ( smb1_nt_create_andx_request )
{ {
// name_length : uint16; // name_length : uint16;

View file

@ -28,7 +28,7 @@ refine connection SMB_Conn += {
BuildHeaderVal(h), BuildHeaderVal(h),
${val.data_len}); ${val.data_len});
if ( ${val.data_len} > 0 ) if ( !get_tree_is_pipe(${h.tid}) && ( ${val.data_len} > 0 ) )
{ {
uint64 offset = read_offsets[${h.mid}]; uint64 offset = read_offsets[${h.mid}];
read_offsets.erase(${h.mid}); read_offsets.erase(${h.mid});
@ -80,7 +80,10 @@ type SMB1_read_andx_response(header: SMB_Header) = record {
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_len; is_pipe : case $context.connection.get_tree_is_pipe(header.tid) of {
true -> pipe_data : SMB_Pipe_message(header, byte_count) &length=data_len;
default -> data : bytestring &length=data_len;
} &requires(data_len);
} &let { } &let {
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;

View file

@ -14,12 +14,21 @@ refine connection SMB_Conn += {
smb_string2stringval(${val.name}), ${val.sub_cmd}); smb_string2stringval(${val.name}), ${val.sub_cmd});
return true; return true;
%} %}
function proc_smb1_transaction_response(header: SMB_Header, val: SMB1_transaction_response): bool function proc_smb1_transaction_response(header: SMB_Header, val: SMB1_transaction_response): bool
%{ %{
//printf("transaction_response\n"); //printf("transaction_response\n");
return true; return true;
%} %}
function proc_smb1_transaction_setup(header: SMB_Header, val: SMB1_transaction_setup): bool
%{
if ( smb1_transaction_setup )
BifEvent::generate_smb1_transaction_setup(bro_analyzer(), bro_analyzer()->Conn(), BuildHeaderVal(header), \
${val.op_code}, ${val.file_id});
return true;
%}
}; };
@ -27,12 +36,19 @@ type SMB1_transaction_data(header: SMB_Header, count: uint16, sub_cmd: uint16,
trans_type: TransactionType ) = case trans_type of { trans_type: TransactionType ) = case trans_type of {
# SMB_MAILSLOT_BROWSE -> mailslot : SMB_MailSlot_message(header.unicode, count); # SMB_MAILSLOT_BROWSE -> mailslot : SMB_MailSlot_message(header.unicode, count);
# SMB_MAILSLOT_LANMAN -> lanman : SMB_MailSlot_message(header.unicode, count); # SMB_MAILSLOT_LANMAN -> lanman : SMB_MailSlot_message(header.unicode, count);
# SMB_RAP -> rap : SMB_Pipe_message(header.unicode, count, sub_cmd); # SMB_RAP -> rap : SMB_Pipe_message(header.unicode, count);
SMB_PIPE -> pipe : SMB_Pipe_message(header.unicode, count, sub_cmd); SMB_PIPE -> pipe : SMB_Pipe_message(header, count);
SMB_UNKNOWN -> unknown : bytestring &restofdata; SMB_UNKNOWN -> unknown : bytestring &restofdata;
# default -> data : bytestring &restofdata; # default -> data : bytestring &restofdata;
}; };
type SMB1_transaction_setup(header: SMB_Header) = record {
op_code : uint16;
file_id : uint16;
} &let {
proc: bool = $context.connection.proc_smb1_transaction_setup(header, this);
}
type SMB1_transaction_request(header: SMB_Header) = record { type SMB1_transaction_request(header: SMB_Header) = record {
word_count : uint8; word_count : uint8;
total_param_count : uint16; total_param_count : uint16;
@ -50,7 +66,7 @@ type SMB1_transaction_request(header: SMB_Header) = record {
data_offset : uint16; data_offset : uint16;
setup_count : uint8; setup_count : uint8;
reserved3 : uint8; reserved3 : uint8;
setup : uint16[setup_count]; setup : SMB1_transaction_setup(header);
byte_count : uint16; byte_count : uint16;
name : SMB_string(header.unicode, offsetof(name)); name : SMB_string(header.unicode, offsetof(name));
@ -59,7 +75,7 @@ type SMB1_transaction_request(header: SMB_Header) = record {
pad2 : padding to data_offset - SMB_Header_length; pad2 : padding to data_offset - SMB_Header_length;
data : SMB1_transaction_data(header, data_count, sub_cmd, determine_transaction_type(setup_count, name)); data : SMB1_transaction_data(header, data_count, sub_cmd, determine_transaction_type(setup_count, name));
} &let { } &let {
sub_cmd : uint16 = setup_count ? setup[0] : 0; sub_cmd : uint16 = setup_count ? setup.op_code : 0;
proc : bool = $context.connection.proc_smb1_transaction_request(header, this); proc : bool = $context.connection.proc_smb1_transaction_request(header, this);
}; };
@ -83,7 +99,7 @@ type SMB1_transaction_response(header: SMB_Header) = record {
pad0 : padding to param_offset - SMB_Header_length; pad0 : padding to param_offset - SMB_Header_length;
parameters : bytestring &length = param_count; parameters : bytestring &length = param_count;
pad1 : padding to data_offset - SMB_Header_length; pad1 : padding to data_offset - SMB_Header_length;
handle_response : case $context.connection.isATSVC() of { handle_response : case $context.connection.get_tree_is_pipe(header.tid) of {
true -> pipe_data : SMB1_transaction_data(header, data_count, 0, SMB_PIPE); true -> pipe_data : SMB1_transaction_data(header, data_count, 0, SMB_PIPE);
false -> unk_data : SMB1_transaction_data(header, data_count, 0, SMB_UNKNOWN); false -> unk_data : SMB1_transaction_data(header, data_count, 0, SMB_UNKNOWN);
}; };

View file

@ -13,6 +13,7 @@ refine connection SMB_Conn += {
function proc_smb1_tree_connect_andx_response(header: SMB_Header, val: SMB1_tree_connect_andx_response): bool function proc_smb1_tree_connect_andx_response(header: SMB_Header, val: SMB1_tree_connect_andx_response): bool
%{ %{
set_tree_is_pipe(${header.tid}, strcmp((const char*) smb_string2stringval(${val.service})->Bytes(), "IPC") == 0);
if ( smb1_tree_connect_andx_response ) if ( smb1_tree_connect_andx_response )
BifEvent::generate_smb1_tree_connect_andx_response(bro_analyzer(), BifEvent::generate_smb1_tree_connect_andx_response(bro_analyzer(),
bro_analyzer()->Conn(), bro_analyzer()->Conn(),

View file

@ -52,7 +52,10 @@ type SMB1_write_andx_request(header: SMB_Header) = record {
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_len; is_pipe : case $context.connection.get_tree_is_pipe(header.tid) of {
true -> pipe_data : SMB_Pipe_message(header, byte_count) &length=data_len;
default -> data : bytestring &length=data_len;
} &requires(data_len);
} &let { } &let {
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;

View file

@ -1 +1,5 @@
event smb1_transaction_request%(c: connection, hdr: SMB1::Header, name: string, sub_cmd: count%); # TODO - Description
event smb1_transaction_request%(c: connection, hdr: SMB1::Header, name: string, sub_cmd: count%);
# TODO - Description
event smb1_transaction_setup%(c: connection, hdr: SMB1::Header, op_code: count, file_id: count%);

View file

@ -1,6 +1,12 @@
## TODO ## TODO - Description
event smb_atsvc_job_add%(c: connection, server: string, job: string%); event smb_pipe_bind_request%(c: connection, hdr: SMB1::Header, uuid: string, version: string%);
## TODO ## TODO - Description
event smb_atsvc_job_id%(c: connection, id: count, status: count%); event smb_pipe_bind_ack_response%(c: connection, hdr: SMB1::Header%);
## TODO - Description
event smb_pipe_request%(c: connection, hdr: SMB1::Header, op_num: count%);
## TODO - Description
event smb_pipe_response%(c: connection, hdr: SMB1::Header%);