},
hexes =
{
- { service = 'dcerpc', proto = 'tcp', client_first = true,
- to_server = { '|05 00|' }, to_client = { '|05 00|' } },
-
{ service = 'dnp3', proto = 'tcp', client_first = true,
to_server = { '|05 64|' }, to_client = { '|05 64|' } },
to_server = { '????|0 0 0 0 0 0 0 1|' },
to_client = { '????|0 0 0 0 0 0 0 1|' } },
--]]
- { service = 'smb', proto = 'tcp', client_first = true,
- to_server = { '|FF|SMB' }, to_client = { '|FF|SMB' } },
-
- { service = 'smb', proto = 'udp', client_first = true,
- to_server = { '|FF|SMB' }, to_client = { '|FF|SMB' } },
{ service = 'ssl', proto = 'tcp', client_first = true,
to_server = { '|16 03|' }, to_client = { '|16 03|' } },
{ service = 'telnet', proto = 'tcp', client_first = true,
to_server = telnet_commands, to_client = telnet_commands },
- }
+ },
+
+ curses = {'dce_udp', 'dce_tcp', 'dce_smb'}
}
---------------------------------------------------------------------------
if (frag_len < sizeof(DceRpcCoHdr))
{
- /* Assume we autodetected incorrectly or that DCE/RPC is not running
+ /* Assume that DCE/RPC is not running
* over the SMB named pipe */
- if (!DCE2_SsnAutodetected(sd) && (sd->trans != DCE2_TRANS_TYPE__SMB))
+ if (sd->trans != DCE2_TRANS_TYPE__SMB)
{
// FIXIT-L PORT_IF_NEEDED segment check, same for all cases below
dce_alert(GID_DCE2, DCE2_CO_FRAG_LEN_LT_HDR,dce_common_stats);
if (DceRpcCoVersMaj(co_hdr) != DCERPC_PROTO_MAJOR_VERS__5)
{
- if (!DCE2_SsnAutodetected(sd) && (sd->trans != DCE2_TRANS_TYPE__SMB))
+ if (sd->trans != DCE2_TRANS_TYPE__SMB)
{
dce_alert(GID_DCE2, DCE2_CO_BAD_MAJOR_VERSION,dce_common_stats);
}
if (DceRpcCoVersMin(co_hdr) != DCERPC_PROTO_MINOR_VERS__0)
{
- if (!DCE2_SsnAutodetected(sd) && (sd->trans != DCE2_TRANS_TYPE__SMB))
+ if (sd->trans != DCE2_TRANS_TYPE__SMB)
{
dce_alert(GID_DCE2, DCE2_CO_BAD_MINOR_VERSION,dce_common_stats);
}
}
if (pdu_type >= DCERPC_PDU_TYPE__MAX)
{
- if (!DCE2_SsnAutodetected(sd) && (sd->trans != DCE2_TRANS_TYPE__SMB))
+ if (sd->trans != DCE2_TRANS_TYPE__SMB)
{
dce_alert(GID_DCE2, DCE2_CO_BAD_PDU_TYPE,dce_common_stats);
}
struct dce2CommonStats
{
PegCount events;
- PegCount sessions_aborted;
- PegCount bad_autodetects;
-
PegCount co_pdus;
PegCount co_bind;
PegCount co_bind_ack;
enum DCE2_SsnFlag
{
DCE2_SSN_FLAG__NONE = 0x0000,
- DCE2_SSN_FLAG__AUTODETECTED = 0x0001,
- DCE2_SSN_FLAG__NO_INSPECT = 0x0002,
- DCE2_SSN_FLAG__SMB2 = 0x0004,
+ DCE2_SSN_FLAG__NO_INSPECT = 0x0001,
+ DCE2_SSN_FLAG__SMB2 = 0x0002,
DCE2_SSN_FLAG__ALL = 0xffff
};
Packet* wire_pkt;
uint64_t alert_mask;
DCE2_Roptions ropts;
- int autodetect_dir;
void* config;
uint32_t cli_seq;
ropts->stub_data = nullptr;
}
-inline void DCE2_SsnSetAutodetected(DCE2_SsnData* sd, Packet* p)
-{
- sd->flags |= DCE2_SSN_FLAG__AUTODETECTED;
- sd->autodetect_dir = p->packet_flags & (PKT_FROM_CLIENT | PKT_FROM_SERVER);
-}
-
-inline int DCE2_SsnAutodetectDir(DCE2_SsnData* sd)
-{
- return sd->autodetect_dir;
-}
-
-inline int DCE2_SsnAutodetected(DCE2_SsnData* sd)
-{
- return sd->flags & DCE2_SSN_FLAG__AUTODETECTED;
-}
-
-inline void DCE2_SsnClearAutodetected(DCE2_SsnData* sd)
-{
- sd->flags &= ~DCE2_SSN_FLAG__AUTODETECTED;
- sd->autodetect_dir = 0;
-}
-
inline void DCE2_SsnSetNoInspect(DCE2_SsnData* sd)
{
sd->flags |= DCE2_SSN_FLAG__NO_INSPECT;
const SmbNtHdr*, const uint8_t, const uint8_t*, uint32_t, DCE2_SmbComInfo&);
static void DCE2_SmbProcessCommand(DCE2_SmbSsnData*, const SmbNtHdr*, const uint8_t*, uint32_t);
static DCE2_SmbRequestTracker* DCE2_SmbInspect(DCE2_SmbSsnData*, const SmbNtHdr*);
-static bool DCE2_SmbAutodetect(Packet* p);
static DCE2_SmbRequestTracker* DCE2_SmbFindRequestTracker(DCE2_SmbSsnData*,
const SmbNtHdr*);
static inline DCE2_Ret DCE2_SmbCheckAndXOffset(const uint8_t*,
}
}
-static bool DCE2_SmbAutodetect(Packet* p)
-{
- if (p->dsize > (sizeof(NbssHdr) + sizeof(SmbNtHdr)))
- {
- NbssHdr* nb_hdr = (NbssHdr*)p->data;
- SmbNtHdr* smb_hdr = (SmbNtHdr*)(p->data + sizeof(NbssHdr));
-
- if ((SmbId(smb_hdr) != DCE2_SMB_ID)
- && (SmbId(smb_hdr) != DCE2_SMB2_ID))
- {
- return false;
- }
-
- switch (NbssType(nb_hdr))
- {
- // FIXIT-L currently all ports are treated as autodetect.
- // On port 139, there is always an initial Session Request / Session Positive/Negative
- // response.
- // These message types were added , to make sure port 139 is treated as smb.
- // Remove once detect/autodetect supported.
- case NBSS_SESSION_TYPE__REQUEST:
- if (DCE2_SsnFromClient(p))
- return true;
- break;
-
- case NBSS_SESSION_TYPE__POS_RESPONSE:
- case NBSS_SESSION_TYPE__NEG_RESPONSE:
- if (DCE2_SsnFromServer(p))
- return true;
- break;
-
- case NBSS_SESSION_TYPE__MESSAGE:
- return true;
- break;
- default:
- break;
- }
- }
-
- return false;
-}
-
static void DCE2_SmbDataFree(DCE2_SmbSsnData* ssd)
{
if (ssd == nullptr)
DCE2_SmbSsnData* dce2_smb_sess = nullptr;
Profile profile(dce2_smb_pstat_new_session);
- //FIXIT-M Re-evaluate after infrastructure/binder support if autodetect here
- //is necessary
-
- if (DCE2_SmbAutodetect(p))
- {
- DebugMessage(DEBUG_DCE_SMB, "DCE over SMB packet detected\n");
- DebugMessage(DEBUG_DCE_SMB, "Creating new session\n");
-
- dce2_smb_sess = set_new_dce2_smb_session(p);
- if ( dce2_smb_sess )
- {
- dce2_smb_sess->dialect_index = DCE2_SENTINEL;
- dce2_smb_sess->max_outstanding_requests = 10; // Until Negotiate/SessionSetupAndX
- dce2_smb_sess->cli_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
- dce2_smb_sess->srv_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
- dce2_smb_sess->pdu_state = DCE2_SMB_PDU_STATE__COMMAND;
- dce2_smb_sess->uid = DCE2_SENTINEL;
- dce2_smb_sess->tid = DCE2_SENTINEL;
- dce2_smb_sess->ftracker.fid_v1 = DCE2_SENTINEL;
- dce2_smb_sess->rtracker.mid = DCE2_SENTINEL;
- dce2_smb_sess->max_file_depth = FileService::get_max_file_depth();
-
- DCE2_ResetRopts(&dce2_smb_sess->sd.ropts);
-
- dce2_smb_stats.smb_sessions++;
- DebugFormat(DEBUG_DCE_SMB,"Created (%p)\n", (void*)dce2_smb_sess);
-
- dce2_smb_sess->sd.trans = DCE2_TRANS_TYPE__SMB;
- dce2_smb_sess->sd.server_policy = config->common.policy;
- dce2_smb_sess->sd.client_policy = DCE2_POLICY__WINXP;
- dce2_smb_sess->sd.wire_pkt = p;
- dce2_smb_sess->sd.config = (void*)config;
-
- DCE2_SsnSetAutodetected(&dce2_smb_sess->sd, p);
- }
- }
-
+ DebugMessage(DEBUG_DCE_SMB, "DCE over SMB packet detected\n");
+ DebugMessage(DEBUG_DCE_SMB, "Creating new session\n");
+
+ dce2_smb_sess = set_new_dce2_smb_session(p);
+ if ( dce2_smb_sess )
+ {
+ dce2_smb_sess->dialect_index = DCE2_SENTINEL;
+ dce2_smb_sess->max_outstanding_requests = 10; // Until Negotiate/SessionSetupAndX
+ dce2_smb_sess->cli_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
+ dce2_smb_sess->srv_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
+ dce2_smb_sess->pdu_state = DCE2_SMB_PDU_STATE__COMMAND;
+ dce2_smb_sess->uid = DCE2_SENTINEL;
+ dce2_smb_sess->tid = DCE2_SENTINEL;
+ dce2_smb_sess->ftracker.fid_v1 = DCE2_SENTINEL;
+ dce2_smb_sess->rtracker.mid = DCE2_SENTINEL;
+ dce2_smb_sess->max_file_depth = FileService::get_max_file_depth();
+
+ DCE2_ResetRopts(&dce2_smb_sess->sd.ropts);
+
+ dce2_smb_stats.smb_sessions++;
+ DebugFormat(DEBUG_DCE_SMB,"Created (%p)\n", (void*)dce2_smb_sess);
+
+ dce2_smb_sess->sd.trans = DCE2_TRANS_TYPE__SMB;
+ dce2_smb_sess->sd.server_policy = config->common.policy;
+ dce2_smb_sess->sd.client_policy = DCE2_POLICY__WINXP;
+ dce2_smb_sess->sd.wire_pkt = p;
+ dce2_smb_sess->sd.config = (void*)config;
+ }
+
return dce2_smb_sess;
}
{
dce2_smb_sess = dce2_create_new_smb_session(p, config);
}
- else
- {
- DCE2_SsnData* sd = (DCE2_SsnData*)dce2_smb_sess;
- sd->wire_pkt = p;
-
- if (DCE2_SsnAutodetected(sd) && !(p->packet_flags & sd->autodetect_dir))
- {
- /* Try to autodetect in opposite direction */
- if (!DCE2_SmbAutodetect(p))
- {
- DebugMessage(DEBUG_DCE_SMB, "Bad autodetect.\n");
- DCE2_SsnNoInspect(sd);
- dce2_smb_stats.sessions_aborted++;
- dce2_smb_stats.bad_autodetects++;
- return nullptr;
- }
- DCE2_SsnClearAutodetected(sd);
- }
- }
+
DebugFormat(DEBUG_DCE_SMB, "Session pointer: %p\n", (void*)dce2_smb_sess);
- // FIXIT-M add remaining session handling logic
-
return dce2_smb_sess;
}
DCE2_ResetRopts(&dce2_smb_sess->sd.ropts);
DCE2_PopPkt(&dce2_smb_sess->sd);
- if (!DCE2_SsnAutodetected(&dce2_smb_sess->sd))
- DisableInspection();
-
delete p->endianness;
p->endianness = nullptr;
}
struct dce2SmbStats
{
-/* FIXIT-M add array based peg counts
- PegCount sessions_autodetected;
-#ifdef DEBUG
- PegCount autoports[65535][DCE2_TRANS_TYPE__MAX];
-#endif
-*/
PegCount events;
- PegCount sessions_aborted;
- PegCount bad_autodetects;
PegCount co_pdus;
PegCount co_bind;
static const PegInfo dce2_smb_pegs[] =
{
{ "events", "total events" },
- { "aborted sessions", "total aborted sessions" },
- { "bad autodetects", "total bad autodetects" },
{ "PDUs", "total connection-oriented PDUs" },
{ "Binds", "total connection-oriented binds" },
{ "Bind acks", "total connection-oriented binds acks" },
DCE2_TcpSsnData* dce2_tcp_sess = nullptr;
Profile profile(dce2_tcp_pstat_new_session);
- // FIXIT-M re-evaluate after infrastructure/binder support if autodetect here
- // is necessary
- if (DCE2_TcpAutodetect(p))
- {
- DebugMessage(DEBUG_DCE_TCP, "DCE over TCP packet detected\n");
- DebugMessage(DEBUG_DCE_TCP, "Creating new session\n");
-
- dce2_tcp_sess = set_new_dce2_tcp_session(p);
+ DebugMessage(DEBUG_DCE_TCP, "DCE over TCP packet detected\n");
+ DebugMessage(DEBUG_DCE_TCP, "Creating new session\n");
- if ( dce2_tcp_sess )
- {
- DCE2_CoInitTracker(&dce2_tcp_sess->co_tracker);
- DCE2_ResetRopts(&dce2_tcp_sess->sd.ropts);
+ dce2_tcp_sess = set_new_dce2_tcp_session(p);
- dce2_tcp_stats.tcp_sessions++;
- DebugFormat(DEBUG_DCE_TCP,"Created (%p)\n", (void*)dce2_tcp_sess);
+ if ( dce2_tcp_sess )
+ {
+ DCE2_CoInitTracker(&dce2_tcp_sess->co_tracker);
+ DCE2_ResetRopts(&dce2_tcp_sess->sd.ropts);
- dce2_tcp_sess->sd.trans = DCE2_TRANS_TYPE__TCP;
- dce2_tcp_sess->sd.server_policy = config->common.policy;
- dce2_tcp_sess->sd.client_policy = DCE2_POLICY__WINXP;
- dce2_tcp_sess->sd.wire_pkt = p;
- dce2_tcp_sess->sd.config = (void*)config;
+ dce2_tcp_stats.tcp_sessions++;
+ DebugFormat(DEBUG_DCE_TCP,"Created (%p)\n", (void*)dce2_tcp_sess);
- DCE2_SsnSetAutodetected(&dce2_tcp_sess->sd, p);
- }
+ dce2_tcp_sess->sd.trans = DCE2_TRANS_TYPE__TCP;
+ dce2_tcp_sess->sd.server_policy = config->common.policy;
+ dce2_tcp_sess->sd.client_policy = DCE2_POLICY__WINXP;
+ dce2_tcp_sess->sd.wire_pkt = p;
+ dce2_tcp_sess->sd.config = (void*)config;
}
return dce2_tcp_sess;
{
dce2_tcp_sess = dce2_create_new_tcp_session(p, config);
}
- else
- {
- DCE2_SsnData* sd = (DCE2_SsnData*)dce2_tcp_sess;
- sd->wire_pkt = p;
-
- if (DCE2_SsnAutodetected(sd) && !(p->packet_flags & sd->autodetect_dir))
- {
- /* Try to autodetect in opposite direction */
- if (!DCE2_TcpAutodetect(p))
- {
- DebugMessage(DEBUG_DCE_TCP, "Bad autodetect.\n");
- DCE2_SsnNoInspect(sd);
- dce2_tcp_stats.sessions_aborted++;
- dce2_tcp_stats.bad_autodetects++;
- return nullptr;
- }
-
- DCE2_SsnClearAutodetected(sd);
- }
- }
DebugFormat(DEBUG_DCE_TCP, "Session pointer: %p\n", (void*)dce2_tcp_sess);
DCE2_ResetRopts(&dce2_tcp_sess->sd.ropts);
DCE2_PopPkt(&dce2_tcp_sess->sd);
- if (!DCE2_SsnAutodetected(&dce2_tcp_sess->sd))
- DisableInspection();
-
delete p->endianness;
p->endianness = nullptr;
}
struct dce2TcpStats
{
-/* FIXIT-M add array based peg counts
- PegCount sessions_autodetected;
-#ifdef DEBUG
- PegCount autoports[65535][DCE2_TRANS_TYPE__MAX];
-#endif
-*/
- /* The common stats block has to be at the beginning followed
- by the protocol specific stats */
-
- /*common stats -defined in common.h*/
+ /* common stats - defined in dce_common.h*/
PegCount events;
- PegCount sessions_aborted;
- PegCount bad_autodetects;
PegCount co_pdus;
PegCount co_bind;
static const PegInfo dce2_tcp_pegs[] =
{
{ "events", "total events" },
- { "aborted sessions", "total aborted sessions" },
- { "bad autodetects", "total bad autodetects" },
{ "PDUs", "total connection-oriented PDUs" },
{ "Binds", "total connection-oriented binds" },
{ "Bind acks", "total connection-oriented binds acks" },
clt->act_trackers = nullptr;
}
-// Tries to determine if a packet is likely to be DCE/RPC over UDP
-static DCE2_TransType DCE2_UdpAutodetect(const Packet* p)
-{
- if (p->dsize >= sizeof(DceRpcClHdr))
- {
- const DceRpcClHdr* cl_hdr = (DceRpcClHdr*)p->data;
-
- if ((DceRpcClRpcVers(cl_hdr) == DCERPC_PROTO_MAJOR_VERS__4) &&
- ((DceRpcClPduType(cl_hdr) == DCERPC_PDU_TYPE__REQUEST) ||
- (DceRpcClPduType(cl_hdr) == DCERPC_PDU_TYPE__RESPONSE) ||
- (DceRpcClPduType(cl_hdr) == DCERPC_PDU_TYPE__FAULT) ||
- (DceRpcClPduType(cl_hdr) == DCERPC_PDU_TYPE__REJECT) ||
- (DceRpcClPduType(cl_hdr) == DCERPC_PDU_TYPE__FACK)) &&
- ((DceRpcClLen(cl_hdr) != 0) &&
- (DceRpcClLen(cl_hdr) + sizeof(DceRpcClHdr)) <= p->dsize))
- {
- return DCE2_TRANS_TYPE__UDP;
- }
- }
-
- return DCE2_TRANS_TYPE__NONE;
-}
-
//-------------------------------------------------------------------------
// class stuff
//-------------------------------------------------------------------------
DCE2_UdpSsnData* dce2_udp_sess = nullptr;
Profile profile(dce2_udp_pstat_new_session);
- // FIXIT-M re-evaluate after infrastructure/binder support if autodetect here
- // is necessary
- if (DCE2_UdpAutodetect(p))
- {
- DebugMessage(DEBUG_DCE_UDP, "DCE over UDP packet detected\n");
- DebugMessage(DEBUG_DCE_UDP, "Creating new session\n");
+ DebugMessage(DEBUG_DCE_UDP, "DCE over UDP packet detected\n");
+ DebugMessage(DEBUG_DCE_UDP, "Creating new session\n");
- dce2_udp_sess = set_new_dce2_udp_session(p);
-
- DCE2_ResetRopts(&dce2_udp_sess->sd.ropts);
+ dce2_udp_sess = set_new_dce2_udp_session(p);
- dce2_udp_stats.udp_sessions++;
- DebugFormat(DEBUG_DCE_UDP,"Created (%p)\n", (void*)dce2_udp_sess);
+ DCE2_ResetRopts(&dce2_udp_sess->sd.ropts);
- dce2_udp_sess->sd.trans = DCE2_TRANS_TYPE__UDP;
- dce2_udp_sess->sd.wire_pkt = p;
- dce2_udp_sess->sd.config = (void*)config;
+ dce2_udp_stats.udp_sessions++;
+ DebugFormat(DEBUG_DCE_UDP,"Created (%p)\n", (void*)dce2_udp_sess);
- DCE2_SsnSetAutodetected(&dce2_udp_sess->sd, p);
- }
+ dce2_udp_sess->sd.trans = DCE2_TRANS_TYPE__UDP;
+ dce2_udp_sess->sd.wire_pkt = p;
+ dce2_udp_sess->sd.config = (void*)config;
return dce2_udp_sess;
}
{
dce2_udp_sess = dce2_create_new_udp_session(p, config);
}
- else
- {
- DCE2_SsnData* sd = (DCE2_SsnData*)dce2_udp_sess;
- sd->wire_pkt = p;
-
- if (DCE2_SsnAutodetected(sd) && !(p->packet_flags & sd->autodetect_dir))
- {
- /* Try to autodetect in opposite direction */
- if (!DCE2_UdpAutodetect(p))
- {
- DebugMessage(DEBUG_DCE_UDP, "Bad autodetect.\n");
- DCE2_SsnNoInspect(sd);
- dce2_udp_stats.sessions_aborted++;
- dce2_udp_stats.bad_autodetects++;
- return nullptr;
- }
-
- DCE2_SsnClearAutodetected(sd);
- }
- }
DebugFormat(DEBUG_DCE_UDP, "Session pointer: %p\n", (void*)dce2_udp_sess);
DCE2_ResetRopts(&dce2_udp_sess->sd.ropts);
DCE2_PopPkt(&dce2_udp_sess->sd);
- if (!DCE2_SsnAutodetected(&dce2_udp_sess->sd))
- DisableInspection();
-
delete p->endianness;
p->endianness = nullptr;
}
/*common stats -defined in common.h*/
PegCount events;
- PegCount sessions_aborted;
- PegCount bad_autodetects;
/*DCE UDP specific*/
PegCount udp_sessions;
static const PegInfo dce2_udp_pegs[] =
{
{ "events", "total events" },
- { "aborted sessions", "total aborted sessions" },
- { "bad autodetects", "total bad autodetects" },
{ "udp sessions", "total udp sessions" },
{ "udp packets", "total udp packets" },
{ "Requests", "total connection-less requests" },
if (data_len < sizeof(DceRpcClHdr))
{
- // FIXIT-M currently we always do autodetect. Uncomment once
- // detect/autodetect is supported.
-/*
- if (!DCE2_SsnAutodetected(sd))
- dce_alert(GID_DCE2, DCE2_CL_DATA_LT_HDR, (dce2CommonStats*)&dce2_udp_stats);
-*/
+ dce_alert(GID_DCE2, DCE2_CL_DATA_LT_HDR, (dce2CommonStats*)&dce2_udp_stats);
return;
}
{
if (DceRpcClRpcVers(cl_hdr) != DCERPC_PROTO_MAJOR_VERS__4)
{
- // FIXIT-M currently we always do autodetect. Uncomment once
- // detect/autodetect is supported.
- /* If we autodetected the session, we probably guessed wrong */
- /* if (!DCE2_SsnAutodetected(sd))
- dce_alert(GID_DCE2, DCE2_CL_BAD_MAJOR_VERSION, (dce2CommonStats*)&dce2_udp_stats);
- */
+ dce_alert(GID_DCE2, DCE2_CL_BAD_MAJOR_VERSION, (dce2CommonStats*)&dce2_udp_stats);
return DCE2_RET__ERROR;
}
if (DceRpcClPduType(cl_hdr) >= DCERPC_PDU_TYPE__MAX)
{
- // FIXIT-M currently we always do autodetect. Uncomment once
- // detect/autodetect is supported.
-/*
- if (!DCE2_SsnAutodetected(sd))
- dce_alert(GID_DCE2, DCE2_CL_BAD_PDU_TYPE, (dce2CommonStats*)&dce2_udp_stats);
-*/
+ dce_alert(GID_DCE2, DCE2_CL_BAD_PDU_TYPE, (dce2CommonStats*)&dce2_udp_stats);
return DCE2_RET__ERROR;
}
static void DCE2_ClFragReassemble(DCE2_SsnData* sd, DCE2_ClActTracker* at, const
DceRpcClHdr* cl_hdr)
{
- uint8_t dce2_cl_rbuf[IP_MAXPACKET];
- DCE2_ClFragTracker* ft = &at->frag_tracker;
- uint8_t* rdata = dce2_cl_rbuf;
+ uint8_t dce2_cl_rbuf[IP_MAXPACKET];
+ DCE2_ClFragTracker* ft = &at->frag_tracker;
+ uint8_t* rdata = dce2_cl_rbuf;
uint16_t rlen = sizeof(dce2_cl_rbuf);
- DCE2_ClFragNode* fnode;
- uint32_t stub_len = 0;
+ DCE2_ClFragNode* fnode;
+ uint32_t stub_len = 0;
Profile profile(dce2_udp_pstat_cl_reass);
stub_len += fnode->frag_len;
}
- Packet* rpkt = DCE2_GetRpkt(sd->wire_pkt, DCE2_RPKT_TYPE__UDP_CL_FRAG, dce2_cl_rbuf, stub_len);
+ Packet* rpkt = DCE2_GetRpkt(sd->wire_pkt, DCE2_RPKT_TYPE__UDP_CL_FRAG, dce2_cl_rbuf, stub_len);
if (rpkt == nullptr)
{
DebugFormat(DEBUG_DCE_UDP,
Options that are meaningful to all inspectors, such as policy, are
copied into each inspector configuration.
-The address/port mapping is handled by the binder. Since the
-infrastructure has no support for "autodetect" all ports are treated
-the same currently and autodetection performed. Default autodetect
-ranges were temporarly replaced by a single port default.
+The address/port mapping is handled by the binder. Autodetect
+functionality is replaced by wizard curses.
The Snort 2x global configuration is now rolled into server
configuration.
-
-Note: Some logic related to DCE segmentation and packet stack seems
-unnecessary. It is assumed that the only case for which segmentation
-logic will come into play is if the fragment size is > MAX_PAF_MAX
-resulting in a partial fragment being delivered to the inspector. All
-other logic has been removed with comment #PORT_IF_NEEDED.
set(FILE_LIST
+ curses.cc
+ curses.h
magic.cc
magic.h
hexes.cc
file_list = \
+curses.cc \
+curses.h \
magic.cc magic.h \
hexes.cc \
spells.cc \
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2016-2016 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// curses.cc author Maya Dagon <mdagon@cisco.com>
+
+#include "curses.h"
+
+#include <ctype.h>
+#include "flow/flow.h"
+#include "protocols/packet.h"
+
+using namespace std;
+
+enum DceRpcPduType
+{
+ DCERPC_PDU_TYPE__REQUEST = 0,
+ DCERPC_PDU_TYPE__PING,
+ DCERPC_PDU_TYPE__RESPONSE,
+ DCERPC_PDU_TYPE__FAULT,
+ DCERPC_PDU_TYPE__WORKING,
+ DCERPC_PDU_TYPE__NOCALL,
+ DCERPC_PDU_TYPE__REJECT,
+ DCERPC_PDU_TYPE__ACK,
+ DCERPC_PDU_TYPE__CL_CANCEL,
+ DCERPC_PDU_TYPE__FACK,
+ DCERPC_PDU_TYPE__CANCEL_ACK,
+ DCERPC_PDU_TYPE__BIND,
+ DCERPC_PDU_TYPE__BIND_ACK,
+ DCERPC_PDU_TYPE__BIND_NACK,
+ DCERPC_PDU_TYPE__ALTER_CONTEXT,
+ DCERPC_PDU_TYPE__ALTER_CONTEXT_RESP,
+ DCERPC_PDU_TYPE__AUTH3,
+ DCERPC_PDU_TYPE__SHUTDOWN,
+ DCERPC_PDU_TYPE__CO_CANCEL,
+ DCERPC_PDU_TYPE__ORPHANED,
+ DCERPC_PDU_TYPE__MICROSOFT_PROPRIETARY_OUTLOOK2003_RPC_OVER_HTTP,
+ DCERPC_PDU_TYPE__MAX
+};
+
+/* Version 4 is for Connectionless
+ * Version 5 is for Connection oriented */
+enum DceRpcProtoMajorVers
+{
+ DCERPC_PROTO_MAJOR_VERS__4 = 4,
+ DCERPC_PROTO_MAJOR_VERS__5 = 5
+};
+
+enum DceRpcProtoMinorVers
+{
+ DCERPC_PROTO_MINOR_VERS__0 = 0,
+ DCERPC_PROTO_MINOR_VERS__1 = 1
+};
+
+bool dce_udp_curse(const uint8_t* data, unsigned len, CurseTracker*)
+{
+ const uint8_t dcerpc_cl_hdr_len = 80;
+ const uint8_t cl_len_offset = 74;
+
+ if (len >= dcerpc_cl_hdr_len)
+ {
+ uint8_t version = data[0];
+ uint8_t pdu_type = data[1];
+ bool little_endian = ((data[4] & 0x10) >> 4) ? true : false;
+ uint16_t cl_len;
+
+#ifdef WORDS_BIGENDIAN
+ if (!little_endian)
+#else
+ if (little_endian)
+#endif /* WORDS_BIGENDIAN */
+ cl_len = (data[cl_len_offset+1] << 8) | data[cl_len_offset];
+ else
+ cl_len = (data[cl_len_offset] << 8) | data[cl_len_offset+1];
+
+ if ((version == DCERPC_PROTO_MAJOR_VERS__4) &&
+ ((pdu_type == DCERPC_PDU_TYPE__REQUEST) ||
+ (pdu_type == DCERPC_PDU_TYPE__RESPONSE) ||
+ (pdu_type == DCERPC_PDU_TYPE__FAULT) ||
+ (pdu_type == DCERPC_PDU_TYPE__REJECT) ||
+ (pdu_type == DCERPC_PDU_TYPE__FACK)) &&
+ ((cl_len != 0) &&
+ (cl_len + (unsigned)dcerpc_cl_hdr_len) <= len))
+ return true;
+ }
+
+ return false;
+}
+
+bool dce_tcp_curse(const uint8_t* data, unsigned len, CurseTracker* tracker)
+{
+ const uint8_t dce_rpc_co_hdr_len = 16;
+
+ uint32_t n = 0;
+ while (n < len)
+ {
+ switch (tracker->state)
+ {
+ case STATE_0: // check major version
+ {
+ if (data[n] != DCERPC_PROTO_MAJOR_VERS__5)
+ {
+ // go to bad state
+ tracker->state = STATE_10;
+ return false;
+ }
+ tracker->state = (DCE_States)((int)tracker->state + 1);
+ break;
+ }
+
+ case STATE_1: // check minor version
+ {
+ if (data[n] != DCERPC_PROTO_MINOR_VERS__0)
+ {
+ // go to bad state
+ tracker->state = STATE_10;
+ return false;
+ }
+ tracker->state = (DCE_States)((int)tracker->state + 1);
+ break;
+ }
+
+ case STATE_2: // pdu_type
+ {
+ uint8_t pdu_type = data[n];
+ if ((pdu_type != DCERPC_PDU_TYPE__BIND) &&
+ (pdu_type != DCERPC_PDU_TYPE__BIND_ACK))
+ {
+ // go to bad state
+ tracker->state = STATE_10;
+ return false;
+ }
+ tracker->state = (DCE_States)((int)tracker->state + 1);
+ break;
+ }
+
+ case STATE_4: //little endian
+ tracker->helper = (data[n] & 0x10) << 20;
+ tracker->state = (DCE_States)((int)tracker->state + 1);
+ break;
+ case STATE_8:
+ tracker->helper |= data[n];
+ tracker->state = (DCE_States)((int)tracker->state + 1);
+ break;
+ case STATE_9:
+ {
+#ifdef WORDS_BIGENDIAN
+ if (!(tracker->helper >> 24))
+#else
+ if (tracker->helper >> 24)
+#endif /* WORDS_BIGENDIAN */
+ tracker->helper = (data[n] << 8) | (tracker->helper & 0XFF);
+ else
+ {
+ tracker->helper <<=8;
+ tracker->helper |= data[n];
+ }
+
+ if (tracker->helper >= dce_rpc_co_hdr_len)
+ return true;
+
+ tracker->state = STATE_10;
+ break;
+ }
+
+ case STATE_10:
+ // no match
+ return false;
+ default:
+ tracker->state = (DCE_States)((int)tracker->state + 1);
+ break;
+ }
+ n++;
+ }
+
+ return false;
+}
+
+bool dce_smb_curse(const uint8_t* data, unsigned len, CurseTracker* tracker)
+{
+ const uint32_t dce_smb_id = 0xff534d42; /* \xffSMB */
+ const uint32_t dce_smb2_id = 0xfe534d42; /* \xfeSMB */
+ const uint8_t nbss_type_message = 0;
+
+ uint32_t n = 0;
+ while (n < len)
+ {
+ switch (tracker->state)
+ {
+ case STATE_0:
+ {
+ if (data[n] != nbss_type_message)
+ {
+ tracker->state = STATE_8;
+ return false;
+ }
+ tracker->state = (DCE_States)((int)tracker->state + 1);
+ break;
+ }
+ case STATE_4:
+ {
+ tracker->helper = data[n];
+ tracker->state = (DCE_States)((int)tracker->state + 1);
+ break;
+ }
+ case STATE_5:
+ case STATE_6:
+ {
+ tracker->helper <<= 8;
+ tracker->helper |= data[n];
+ tracker->state = (DCE_States)((int)tracker->state + 1);
+ break;
+ }
+
+ case STATE_7:
+ {
+ tracker->helper <<= 8;
+ tracker->helper |= data[n];
+ if ((tracker->helper == dce_smb_id) || (tracker->helper == dce_smb2_id))
+ return true;
+
+ tracker->state = (DCE_States)((int)tracker->state + 1);
+ break;
+ }
+
+ case STATE_8:
+ // no match
+ return false;
+
+ default:
+ tracker->state = (DCE_States)((int)tracker->state + 1);
+ break;
+ }
+ n++;
+ }
+
+ return false;
+}
+
+// map between service and curse details
+map<string, CurseDetails> curse_map
+{
+ // service_name alg is_tcp
+ { "dce_udp", { dce_udp_curse, false }},
+ { "dce_tcp", { dce_tcp_curse, true }},
+ { "dce_smb", { dce_smb_curse, true }},
+};
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2016-2016 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// curses.h author Maya Dagon <mdagon@cisco.com>
+
+#ifndef CURSES_H
+#define CURSES_H
+
+#include <ctype.h>
+#include <map>
+#include "flow/flow.h"
+#include "protocols/packet.h"
+
+enum DCE_States
+{
+ STATE_0 = 0,
+ STATE_1,
+ STATE_2,
+ STATE_3,
+ STATE_4,
+ STATE_5,
+ STATE_6,
+ STATE_7,
+ STATE_8,
+ STATE_9,
+ STATE_10
+};
+
+class CurseTracker
+{
+public:
+ DCE_States state;
+ uint32_t helper;
+
+ CurseTracker() { state = STATE_0; }
+};
+
+typedef bool (* curse_alg)(const uint8_t* data, unsigned len, CurseTracker*);
+
+struct CurseDetails
+{
+ curse_alg alg;
+ bool is_tcp;
+};
+
+// map between service and curse details
+extern std::map<std::string, CurseDetails > curse_map;
+
+#endif
+
-The wizard uses hexes and spells to determine the most likely service on a
-flow. It does not determine the service with certainty; that is the job of
+The wizard uses hexes, spells and curses to determine the most likely service
+on a flow. It does not determine the service with certainty; that is the job of
the service inspector or appId. The goal is to get the most likely service
inspector engaged as quickly as possible.
the limited number of patterns, space is not a concern and each state has
256 byte array of pointers to the next.
+Curses are presently used for binary protocols that require more than pattern
+matching. They use internal algorithms to identify services,
+implemented with custom FSMs.
#include <string>
+#include "curses.h"
#include "magic.h"
using namespace std;
{ "spells", Parameter::PT_LIST, wizard_spells_params, nullptr,
"criteria for text service identification" },
+ { "curses", Parameter::PT_MULTI, "dce_smb | dce_udp | dce_tcp", nullptr,
+ "enable service identification based on internal algorithm" },
+
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
else if ( v.is("spell") )
spells.push_back(v.get_string());
+ else if ( v.is("curses") )
+ curses.push_back(v.get_string());
+
else
return false;
c2s_spells = new SpellBook;
s2c_spells = new SpellBook;
+ curses.clear();
}
else if ( !strcmp(fqn, "wizard.hexes") )
hex = true;
else
add_spells(s2c_spells, service);
}
+
spells.clear();
service.clear();
ProfileStats* get_profile() const override;
MagicBook* get_book(bool c2s, bool hex);
+ std::vector<std::string> get_curse_book()
+ {
+ return curses;
+ }
private:
void add_spells(MagicBook*, std::string&);
std::string service;
std::vector<std::string> spells;
+ std::vector<std::string> curses;
MagicBook* c2s_hexes;
MagicBook* s2c_hexes;
#include "log/messages.h"
#include "host_tracker/host_cache.h"
+#include "curses.h"
#include "magic.h"
#include "wiz_module.h"
// configuration
//-------------------------------------------------------------------------
+struct CurseServiceTracker
+{
+ string service;
+ CurseTracker* tracker;
+};
+
struct Wand
{
const MagicPage* hex;
const MagicPage* spell;
+ vector<CurseServiceTracker> curse_tracker;
};
class Wizard;
void reset(Wand&, bool tcp, bool c2s);
bool cast_spell(Wand&, Flow*, const uint8_t*, unsigned);
bool spellbind(const MagicPage*&, Flow*, const uint8_t*, unsigned);
+ bool cursebind(vector<CurseServiceTracker>&,Flow*, const uint8_t*, unsigned);
public:
MagicBook* c2s_hexes;
MagicBook* c2s_spells;
MagicBook* s2c_spells;
+ vector<string> curse_book;
};
//-------------------------------------------------------------------------
MagicSplitter::~MagicSplitter()
{
wizard->rem_ref();
+
+ // release trackers
+ for (unsigned i=0; i<wand.curse_tracker.size(); i++)
+ delete wand.curse_tracker[i].tracker;
}
// FIXIT-M stop search on hit and failure (no possible match)
c2s_spells = m->get_book(true, false);
s2c_spells = m->get_book(false, false);
+ curse_book = m->get_curse_book();
}
Wizard::~Wizard()
delete s2c_spells;
}
-void Wizard::reset(Wand& w, bool /*tcp*/, bool c2s)
+void Wizard::reset(Wand& w, bool tcp, bool c2s)
{
if ( c2s )
{
w.hex = s2c_hexes->page1();
w.spell = s2c_spells->page1();
}
+
+ if (w.curse_tracker.empty())
+ {
+ for ( auto service:curse_book )
+ {
+ if (tcp == curse_map[service].is_tcp)
+ {
+ if (tcp)
+ w.curse_tracker.push_back({ service, new CurseTracker });
+ else
+ w.curse_tracker.push_back({ service, nullptr });
+ }
+ }
+ }
}
void Wizard::eval(Packet* p)
if ( w.spell && spellbind(w.spell, f, data, len) )
return true;
+ if (cursebind(w.curse_tracker, f, data, len))
+ return true;
+
return false;
}
+bool Wizard::cursebind(
+ vector<CurseServiceTracker>& curse_tracker, Flow* f, const uint8_t* data, unsigned len)
+{
+ bool match = false;
+
+ for (auto const& p : curse_tracker)
+ {
+ if (curse_map[p.service].alg(data,len, p.tracker))
+ {
+ match = true;
+ f->service = p.service.c_str();
+ break;
+ }
+ }
+
+ if (match)
+ {
+ // FIXIT-H need to make sure Flow's ipproto and service
+ // correspond to HostApplicationEntry's ipproto and service
+ host_cache_add_service(f->server_ip, f->ip_proto, f->server_port, f->service);
+ }
+
+ return match;
+}
+
//-------------------------------------------------------------------------
// api stuff
//-------------------------------------------------------------------------
virtual bool convert(std::istringstream& data);
private:
- bool add_deleted_comment_to_table(std::string table_name, std::string option);
bool add_deleted_comment_to_defaults(std::string option);
bool add_option_to_all(std::string option, const bool val, bool co_only);
bool add_option_to_all(std::string option, const int val, bool co_only);
std::istringstream& stream);
};
-bool Dcerpc::add_deleted_comment_to_table(std::string table_name, std::string option)
-{
- table_api.open_table(table_name);
- bool tmpval = table_api.add_deleted_comment(option);
- table_api.close_table();
-
- return tmpval;
-}
bool Dcerpc::add_option_to_all(std::string option, const bool val, bool co_only)
{
for (auto type : transport)
{
- tmpval = add_deleted_comment_to_table("dce_" + type, option) && tmpval;
+ tmpval = add_deleted_comment_to_table(table_api,"dce_" + type, option) && tmpval;
}
return tmpval;
}
}
};
-// FIXIT-M change to full range - 1025:
-std::map <std::string, std::vector<uint16_t> > autodetect_default_ports
-{
- { "smb", { 1025 }
- },
- { "tcp", { 1026 }
- },
- { "udp", { 1027 }
- }
-};
-
/////////////////////////
// Utility functions
////////////////////////
return tmpval;
}
+bool add_deleted_comment_to_table(TableApi& table_api, std::string table_name, std::string option)
+{
+ table_api.open_table(table_name);
+ bool tmpval = table_api.add_deleted_comment(option);
+ table_api.close_table();
+
+ return tmpval;
+}
+
/////////////////////////////
///// DcerpcServer
/////////////////////////////
{
for (auto type: transport)
{
- autodetect_ports_set[type] = false;
detect_ports_set[type] = false;
}
}
}
}
-// FIXIT-M for now add autodetect ports to binder just like regular detect port.
-// Change autodetect ports to full range once they are supported
-void DcerpcServer::add_default_autodetect_ports(std::string type, std::map<std::string,
- Binder*> bind)
-{
- for (auto port : autodetect_default_ports[type])
- {
- bind[type]->add_when_port(std::to_string(port));
- }
-}
-
// add single port / range
bool DcerpcServer::parse_and_add_ports(std::string ports, std::string type, std::map<std::string,
- Binder*> bind, bool is_detect)
+ Binder*> bind)
{
if (ports.empty())
{
}
}
- if (is_detect)
- {
- detect_ports_set[type] = true;
- }
- else
- {
- autodetect_ports_set[type] = true;
- }
+ detect_ports_set[type] = true;
return true;
}
for (auto transport_type: transport)
{
if (is_detect)
+ {
detect_ports_set[transport_type] = true;
- else
- autodetect_ports_set[transport_type] = true;
+ bind[transport_type]->print_binding(false);
+ }
}
}
{
continue;
}
+ // if this is autodetect- stop here
+ if (!is_detect)
+ {
+ add_deleted_comment_to_table(table_api, table_name[type], "autodetect");
+ continue;
+ }
// remove '[',']'
ports.erase(std::remove(ports.begin(), ports.end(), '['), ports.end());
// remove extra spaces
ports.erase(remove_if(ports.begin(), ports.end(), isspace), ports.end());
- if (!parse_and_add_ports(ports, type, bind, is_detect))
+ if (!parse_and_add_ports(ports, type, bind))
{
return false;
}
{
add_default_ports(type, bind);
}
- if (!autodetect_ports_set[type])
- {
- add_default_autodetect_ports(type, bind);
- }
}
return retval;
bool parse_detect(std::istringstream& data_stream, std::map<std::string, Binder*> bind, bool
is_detect);
void add_default_ports(std::string type, std::map<std::string, Binder*> bind);
- void add_default_autodetect_ports(std::string type, std::map<std::string, Binder*> bind);
bool parse_and_add_ports(std::string ports, std::string type, std::map<std::string,
- Binder*> bind, bool is_detect);
+ Binder*> bind);
bool init_net_created_table();
bool init_new_tables(bool is_default);
bool parse_nets(std::istringstream& data_stream, std::map<std::string,
bool add_option_to_table(
TableApi&, std::string table_name, std::string option, const bool val);
+
+bool add_deleted_comment_to_table(
+ TableApi&, std::string table_name, std::string option);
} // namespace dce
} // namespace preprocessors