const uint8_t dcerpc_cl_hdr_len = 80;
const uint8_t cl_len_offset = 74;
- if (len >= dcerpc_cl_hdr_len)
+ if ( len >= dcerpc_cl_hdr_len )
{
uint8_t version = data[0];
uint8_t pdu_type = data[1];
uint16_t cl_len;
#ifdef WORDS_BIGENDIAN
- if (!little_endian)
+ if ( !little_endian )
#else
- if (little_endian)
+ 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))
+ if ( (version == DCERPC_PROTO_MAJOR_VERS__4) and
+ ((pdu_type == DCERPC_PDU_TYPE__REQUEST) or
+ (pdu_type == DCERPC_PDU_TYPE__RESPONSE) or
+ (pdu_type == DCERPC_PDU_TYPE__FAULT) or
+ (pdu_type == DCERPC_PDU_TYPE__REJECT) or
+ (pdu_type == DCERPC_PDU_TYPE__FACK)) and
+ ((cl_len != 0) and
+ (cl_len + (unsigned)dcerpc_cl_hdr_len) <= len) )
return true;
}
CurseTracker::DCE& dce = tracker->dce;
uint32_t n = 0;
- while (n < len)
+ while ( n < len )
{
- switch (dce.state)
+ switch ( dce.state )
{
case STATE_0: // check major version
- if (data[n] != DCERPC_PROTO_MAJOR_VERS__5)
+ if ( data[n] != DCERPC_PROTO_MAJOR_VERS__5 )
{
// go to bad state
dce.state = STATE_10;
+
return false;
}
+
dce.state = (DCE_State)((int)dce.state + 1);
break;
case STATE_1: // check minor version
- if (data[n] != DCERPC_PROTO_MINOR_VERS__0)
+ if ( data[n] != DCERPC_PROTO_MINOR_VERS__0 )
{
// go to bad state
dce.state = STATE_10;
+
return false;
}
+
dce.state = (DCE_State)((int)dce.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))
+
+ if ( (pdu_type != DCERPC_PDU_TYPE__BIND) and
+ (pdu_type != DCERPC_PDU_TYPE__BIND_ACK) )
{
// go to bad state
dce.state = STATE_10;
+
return false;
}
+
dce.state = (DCE_State)((int)dce.state + 1);
break;
}
break;
case STATE_9:
#ifdef WORDS_BIGENDIAN
- if (!(dce.helper >> 24))
+ if ( !(dce.helper >> 24) )
#else
- if (dce.helper >> 24)
+ if ( dce.helper >> 24 )
#endif /* WORDS_BIGENDIAN */
dce.helper = (data[n] << 8) | (dce.helper & 0XFF);
else
dce.helper |= data[n];
}
- if (dce.helper >= dce_rpc_co_hdr_len)
+ if ( dce.helper >= dce_rpc_co_hdr_len )
return true;
dce.state = STATE_10;
dce.state = (DCE_State)((int)dce.state + 1);
break;
}
+
n++;
}
{
const uint32_t dce_smb_id = 0xff534d42; /* \xffSMB */
const uint32_t dce_smb2_id = 0xfe534d42; /* \xfeSMB */
- const uint8_t session_request = 0x81, session_response = 0x82,
- session_message = 0x00;
+ const uint8_t session_request = 0x81, session_response = 0x82, session_message = 0x00;
CurseTracker::DCE& dce = tracker->dce;
uint32_t n = 0;
- while (n < len)
+ while ( n < len )
{
- switch (dce.state)
+ switch ( dce.state )
{
case STATE_0:
- if (data[n] == session_message)
+ if ( data[n] == session_message )
{
dce.state = (DCE_State)((int)dce.state + 2);
break;
}
- if (data[n] == session_request || data[n] == session_response)
+ if ( data[n] == session_request or data[n] == session_response )
{
dce.state = (DCE_State)((int)dce.state + 1);
+
return false;
}
dce.state = STATE_9;
+
return false;
case STATE_1:
- if (data[n] == session_message)
+ if ( data[n] == session_message )
{
dce.state = (DCE_State)((int)dce.state + 1);
break;
}
dce.state = STATE_9;
+
return false;
case STATE_5:
case STATE_8:
dce.helper <<= 8;
dce.helper |= data[n];
- if ((dce.helper == dce_smb_id) || (dce.helper == dce_smb2_id))
+
+ if ( (dce.helper == dce_smb_id) or (dce.helper == dce_smb2_id) )
return true;
dce.state = (DCE_State)((int)dce.state + 1);
dce.state = (DCE_State)((int)dce.state + 1);
break;
}
+
n++;
}
// if the state is set to MMS_STATE__SEARCH it means we most likely
// have a split pipelined message coming through and will need to
// reset the state
- if (mms.state == MMS_STATE__SEARCH)
+ if ( mms.state == MMS_STATE__SEARCH )
{
mms.state = mms.last_state;
}
};
uint32_t idx = 0;
- while (idx < len)
+ while ( idx < len )
{
- switch (mms.state)
+ switch ( mms.state )
{
case MMS_STATE__TPKT_VER:
{
// . . . . x x x x Destination Reference
// x x x x . . . . PDU Type
const uint32_t MMS_COTP_PDU_DT_DATA = 0x0F;
- if (data[idx] >> 0x04 != MMS_COTP_PDU_DT_DATA)
+
+ if ( data[idx] >> 0x04 != MMS_COTP_PDU_DT_DATA )
{
mms.state = MMS_STATE__NOT_FOUND;
break;
}
+
mms.state = MMS_STATE__COTP_TPDU_NUM;
break;
}
MMS_OSI_SESSION_SPDU_AC = 0x0E,
};
- switch (data[idx])
+ switch ( data[idx] )
{
// check for a known MMS message tag in the event Session/Pres/ACSE aren't used
case MMS_CONFIRMED_REQUEST_TAG: // fallthrough intentional
case MMS_STATE__MMS:
{
// loop through the remaining bytes in the buffer checking for known MMS tags
- for (uint32_t i=idx; i < len; i++)
+ for ( uint32_t i=idx; i < len; i++ )
{
// for each remaining byte check to see if it is in the known tag map
- switch (data[i])
+ switch ( data[i] )
{
case MMS_CONFIRMED_REQUEST_TAG: // fallthrough intentional
case MMS_CONFIRMED_RESPONSE_TAG: // fallthrough intentional
}
// exit the loop when a state has been determined
- if (mms.state == MMS_STATE__NOT_FOUND
+ if ( mms.state == MMS_STATE__NOT_FOUND
or mms.state == MMS_STATE__SEARCH
- or mms.state == MMS_STATE__FOUND)
+ or mms.state == MMS_STATE__FOUND )
{
break;
}
}
+
break;
}
case MMS_STATE__FOUND:
{
mms.state = MMS_STATE__TPKT_VER;
+
return true;
}
case MMS_STATE__NOT_FOUND:
{
mms.state = MMS_STATE__TPKT_VER;
+
return false;
}
break;
}
}
+
idx++;
}
mms.last_state = mms.state;
mms.state = MMS_STATE__SEARCH;
+
return false;
}
{
CurseTracker::SSL& ssl = tracker->ssl;
- if (ssl.state == SSL_State::SSL_NOT_FOUND)
- {
+ if ( ssl.state == SSL_State::SSL_NOT_FOUND )
return false;
- }
- else if (ssl.state == SSL_State::SSL_FOUND)
- {
+ else if ( ssl.state == SSL_State::SSL_FOUND )
return true;
- }
- for (unsigned i = 0; i < len; ++i)
+ for ( unsigned i = 0; i < len; ++i )
{
uint8_t val = data[i];
- switch (ssl.state)
+ switch ( ssl.state )
{
case SSL_State::BYTE_0_LEN_MSB:
- if ((val & SSL_Const::sslv2_msb_set) == 0)
+ if ( (val & SSL_Const::sslv2_msb_set) == 0 )
{
ssl.state = SSL_State::SSL_NOT_FOUND;
+
return false;
}
+
ssl.total_len = (val & (~SSL_Const::sslv2_msb_set)) << 8;
ssl.state = SSL_State::BYTE_1_LEN_LSB;
break;
case SSL_State::BYTE_1_LEN_LSB:
ssl.total_len |= val;
- if (ssl.total_len < SSL_Const::hdr_len)
+ if ( ssl.total_len < SSL_Const::hdr_len )
{
ssl.state = SSL_State::SSL_NOT_FOUND;
+
return false;
}
+
ssl.total_len -= SSL_Const::hdr_len;
ssl.state = SSL_State::BYTE_2_CLIENT_HELLO;
break;
case SSL_State::BYTE_2_CLIENT_HELLO:
- if (val != SSL_Const::client_hello)
+ if ( val != SSL_Const::client_hello )
{
ssl.state = SSL_State::SSL_NOT_FOUND;
+
return false;
}
+
ssl.state = SSL_State::BYTE_3_MAX_MINOR_VER;
break;
case SSL_State::BYTE_3_MAX_MINOR_VER:
- if (val > SSL_Const::sslv3_max_minor_ver)
+ if ( val > SSL_Const::sslv3_max_minor_ver )
{
ssl.state = SSL_State::SSL_NOT_FOUND;
+
return false;
}
+
ssl.state = SSL_State::BYTE_4_V3_MAJOR;
break;
case SSL_State::BYTE_4_V3_MAJOR:
- if (val > SSL_Const::sslv3_major_ver)
+ if ( val > SSL_Const::sslv3_major_ver )
{
ssl.state = SSL_State::SSL_NOT_FOUND;
+
return false;
}
+
ssl.state = SSL_State::BYTE_5_SPECS_LEN_MSB;
break;
case SSL_State::BYTE_6_SPECS_LEN_LSB:
ssl.specs_len |= val;
- if (ssl.total_len < ssl.specs_len)
+
+ if ( ssl.total_len < ssl.specs_len )
{
ssl.state = SSL_State::SSL_NOT_FOUND;
+
return false;
}
+
ssl.total_len -= ssl.specs_len;
ssl.state = SSL_State::BYTE_7_SSNID_LEN_MSB;
break;
case SSL_State::BYTE_8_SSNID_LEN_LSB:
ssl.ssnid_len |= val;
- if (ssl.total_len < ssl.ssnid_len)
+
+ if ( ssl.total_len < ssl.ssnid_len )
{
ssl.state = SSL_State::SSL_NOT_FOUND;
+
return false;
}
+
ssl.total_len -= ssl.ssnid_len;
ssl.state = SSL_State::BYTE_9_CHLNG_LEN_MSB;
break;
case SSL_State::BYTE_10_CHLNG_LEN_LSB:
ssl.chlng_len |= val;
- if (ssl.total_len < ssl.chlng_len)
+
+ if ( ssl.total_len < ssl.chlng_len )
{
ssl.state = SSL_State::SSL_NOT_FOUND;
+
return false;
}
+
ssl.state = SSL_State::SSL_FOUND;
+
return true;
default:
bool CurseBook::add_curse(const char* key)
{
- for (const CurseDetails& curse : curse_map)
+ for ( const CurseDetails& curse : curse_map )
{
- if (curse.name == key)
+ if ( curse.name == key )
{
- if (curse.is_tcp)
+ if ( curse.is_tcp )
tcp_curses.emplace_back(&curse);
else
non_tcp_curses.emplace_back(&curse);
+
return true;
}
}
+
return false;
}
const vector<const CurseDetails*>& CurseBook::get_curses(bool tcp) const
{
- if (tcp)
+ if ( tcp )
return tcp_curses;
+
return non_tcp_curses;
}
auto test = [&](uint32_t incr_by,const uint8_t* ch)
{
uint32_t i = 0;
- while (i <= max_detect)
+ while ( i <= max_detect )
{
- if ((i + incr_by - 1) < max_detect)
+ if ( (i + incr_by - 1) < max_detect )
{
CHECK(tracker.ssl.state == static_cast<SSL_State>(i));
CHECK_FALSE(ssl_v2_curse(&ch[i],sizeof(uint8_t) * incr_by,&tracker));
CHECK(ssl_v2_curse(&ch[i],sizeof(uint8_t) * incr_by,&tracker));
CHECK(tracker.ssl.state == SSL_State::SSL_FOUND);
}
+
i += incr_by;
}
//subsequent checks must return found
ch_data[fail_at_byte] = bad_data[fail_at_byte];
- for (uint32_t i = 0; i <= fail_at_byte; i++)
+ for ( uint32_t i = 0; i <= fail_at_byte; i++ )
{
- if (i < fail_at_byte)
+ if ( i < fail_at_byte )
{
CHECK(tracker.ssl.state == static_cast<SSL_State>(i));
CHECK_FALSE(ssl_v2_curse(&ch_data[i],sizeof(uint8_t),&tracker));
const TraceOption* WizardModule::get_trace_options() const
{
static const TraceOption wizard_trace_options(nullptr, 0, nullptr);
+
return &wizard_trace_options;
}
else if ( v.is("client_first") )
return true;
- else if ( v.is("hex") || v.is("spell") )
+ else if ( v.is("hex") or v.is("spell") )
{
- if (c2s)
+ if ( c2s )
c2s_patterns.emplace_back(v.get_string());
else
s2c_patterns.emplace_back(v.get_string());
curses = new CurseBook;
}
- else if ( !strcmp(fqn, "wizard.hexes") || !strcmp(fqn, "wizard.spells") )
+ else if ( !strcmp(fqn, "wizard.hexes") or !strcmp(fqn, "wizard.spells") )
{
if ( idx > 0 )
{
s2c_patterns.clear();
}
}
- else if ( !strcmp(fqn, "wizard.hexes.to_client") || !strcmp(fqn, "wizard.spells.to_client") )
+ else if ( !strcmp(fqn, "wizard.hexes.to_client") or !strcmp(fqn, "wizard.spells.to_client") )
c2s = false;
- else if ( !strcmp(fqn, "wizard.hexes.to_server") || !strcmp(fqn, "wizard.spells.to_server") )
+ else if ( !strcmp(fqn, "wizard.hexes.to_server") or !strcmp(fqn, "wizard.spells.to_server") )
c2s = true;
return true;
{
ParseError("Invalid %s '%s' for service '%s'",
hex ? "hex" : "spell", p.c_str(), service.c_str());
+
return false;
}
else if ( service != val )
if ( service.empty() )
{
ParseError("Hexes must have a service name");
+
return false;
}
- if ( c2s_patterns.empty() && s2c_patterns.empty() )
+ if ( c2s_patterns.empty() and s2c_patterns.empty() )
{
ParseError("Hexes must have at least one pattern");
+
return false;
}
if ( !add_spells(c2s_hexes, service, c2s_patterns, true) )
if ( service.empty() )
{
ParseError("Spells must have a service name");
+
return false;
}
- if ( c2s_patterns.empty() && s2c_patterns.empty() )
+ if ( c2s_patterns.empty() and s2c_patterns.empty() )
{
ParseError("Spells must have at least one pattern");
+
return false;
}
if ( !add_spells(c2s_spells, service, c2s_patterns, false) )
c2s_hexes = nullptr;
break;
}
+
return b;
}
{
CurseBook* b = curses;
curses = nullptr;
+
return b;
}
StreamSplitter* get_splitter(bool) override;
inline bool finished(Wand& w)
- { return !w.hex && !w.spell && w.curse_tracker.empty(); }
- void reset(Wand&, bool tcp, bool c2s);
+ { return !w.hex and !w.spell and w.curse_tracker.empty(); }
+
+ void reset(Wand&, bool, bool);
+
bool cast_spell(Wand&, Flow*, const uint8_t*, unsigned, uint16_t&);
bool spellbind(const MagicPage*&, Flow*, const uint8_t*, unsigned, const MagicPage*&);
bool cursebind(const vector<CurseServiceTracker>&, Flow*, const uint8_t*, unsigned);
wizard->rem_ref();
// release trackers
- for (unsigned i = 0; i < wand.curse_tracker.size(); i++)
+ for ( unsigned i = 0; i < wand.curse_tracker.size(); i++ )
delete wand.curse_tracker[i].tracker;
}
to_server() ? "c2s" : "s2c", pkt->flow->service);
count_hit(pkt->flow);
wizard_processed_bytes = 0;
+
return STOP;
}
- else if ( wizard->finished(wand) || bytes_scanned >= max(pkt->flow) )
+ else if ( wizard->finished(wand) or bytes_scanned >= max(pkt->flow) )
{
count_miss(pkt->flow);
trace_logf(wizard_trace, pkt, "%s streaming search abandoned\n", to_server() ? "c2s" : "s2c");
wizard_processed_bytes = 0;
- if (!pkt->flow->flags.svc_event_generated)
+
+ if ( !pkt->flow->flags.svc_event_generated )
{
DataBus::publish(FLOW_NO_SERVICE_EVENT, pkt);
pkt->flow->flags.svc_event_generated = true;
}
+
return ABORT;
}
// delayed. Because AppId depends on wizard only for SSH detection and SSH inspector can be
// attached very early, event is raised here after first scan. In the future, wizard should be
// enhanced to abort sooner if it can't detect service.
- if (!pkt->flow->service && !pkt->flow->flags.svc_event_generated)
+ if ( !pkt->flow->service and !pkt->flow->flags.svc_event_generated )
{
DataBus::publish(FLOW_NO_SERVICE_EVENT, pkt);
pkt->flow->flags.svc_event_generated = true;
w.spell = s2c_spells->page1();
}
- if (w.curse_tracker.empty())
+ if ( w.curse_tracker.empty() )
{
vector<const CurseDetails*> pages = curses->get_curses(tcp);
+
for ( const CurseDetails* curse : pages )
{
- if (tcp)
+ if ( tcp )
w.curse_tracker.emplace_back( CurseServiceTracker{ curse, new CurseTracker } );
else
w.curse_tracker.emplace_back( CurseServiceTracker{ curse, nullptr } );
if ( !p->is_udp() )
return;
- if ( !p->data || !p->dsize )
+ if ( !p->data or !p->dsize )
return;
bool c2s = p->is_from_client();
uint16_t udp_processed_bytes = 0;
++tstats.udp_scans;
+
if ( cast_spell(wand, p->flow, p->data, p->dsize, udp_processed_bytes) )
{
trace_logf(wizard_trace, p, "%s datagram search found service %s\n",
const MagicPage*& m, Flow* f, const uint8_t* data, unsigned len, const MagicPage*& bookmark)
{
f->service = m->book.find_spell(data, len, m, bookmark);
+
return f->service != nullptr;
}
bool Wizard::cursebind(const vector<CurseServiceTracker>& curse_tracker, Flow* f,
const uint8_t* data, unsigned len)
{
- for (const CurseServiceTracker& cst : curse_tracker)
+ for ( const CurseServiceTracker& cst : curse_tracker )
{
- if (cst.curse->alg(data, len, cst.tracker))
+ if ( cst.curse->alg(data, len, cst.tracker) )
{
f->service = cst.curse->service;
+
if ( f->service )
return true;
}
Wand& w, Flow* f, const uint8_t* data, unsigned len, uint16_t& wizard_processed_bytes)
{
auto curse_len = len;
-
len = std::min(len, static_cast<unsigned>(max_search_depth - wizard_processed_bytes));
-
wizard_processed_bytes += len;
- if ( w.hex && spellbind(w.hex, f, data, len, w.bookmark) )
+ if ( w.hex and spellbind(w.hex, f, data, len, w.bookmark) )
return true;
- if ( w.spell && spellbind(w.spell, f, data, len, w.bookmark) )
+ if ( w.spell and spellbind(w.spell, f, data, len, w.bookmark) )
return true;
- if (cursebind(w.curse_tracker, f, data, curse_len))
+ if ( cursebind(w.curse_tracker, f, data, curse_len) )
return true;
// If we reach max value of wizard_processed_bytes,
// but not assign any inspector - raise tcp_miss and stop
- if ( !f->service && wizard_processed_bytes >= max_search_depth )
+ if ( !f->service and wizard_processed_bytes >= max_search_depth )
{
w.spell = nullptr;
w.hex = nullptr;