curses.cc (snort3-3.1.29.0) | : | curses.cc (snort3-3.1.30.0) | ||
---|---|---|---|---|
skipping to change at line 76 | skipping to change at line 76 | |||
{ | { | |||
DCERPC_PROTO_MINOR_VERS__0 = 0, | DCERPC_PROTO_MINOR_VERS__0 = 0, | |||
DCERPC_PROTO_MINOR_VERS__1 = 1 | DCERPC_PROTO_MINOR_VERS__1 = 1 | |||
}; | }; | |||
static bool dce_udp_curse(const uint8_t* data, unsigned len, CurseTracker*) | static bool dce_udp_curse(const uint8_t* data, unsigned len, CurseTracker*) | |||
{ | { | |||
const uint8_t dcerpc_cl_hdr_len = 80; | const uint8_t dcerpc_cl_hdr_len = 80; | |||
const uint8_t cl_len_offset = 74; | 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 version = data[0]; | |||
uint8_t pdu_type = data[1]; | uint8_t pdu_type = data[1]; | |||
bool little_endian = ((data[4] & 0x10) >> 4) ? true : false; | bool little_endian = ((data[4] & 0x10) >> 4) ? true : false; | |||
uint16_t cl_len; | uint16_t cl_len; | |||
#ifdef WORDS_BIGENDIAN | #ifdef WORDS_BIGENDIAN | |||
if (!little_endian) | if ( !little_endian ) | |||
#else | #else | |||
if (little_endian) | if ( little_endian ) | |||
#endif /* WORDS_BIGENDIAN */ | #endif /* WORDS_BIGENDIAN */ | |||
cl_len = (data[cl_len_offset+1] << 8) | data[cl_len_offset]; | cl_len = (data[cl_len_offset+1] << 8) | data[cl_len_offset]; | |||
else | else | |||
cl_len = (data[cl_len_offset] << 8) | data[cl_len_offset+1]; | cl_len = (data[cl_len_offset] << 8) | data[cl_len_offset+1]; | |||
if ((version == DCERPC_PROTO_MAJOR_VERS__4) && | if ( (version == DCERPC_PROTO_MAJOR_VERS__4) and | |||
((pdu_type == DCERPC_PDU_TYPE__REQUEST) || | ((pdu_type == DCERPC_PDU_TYPE__REQUEST) or | |||
(pdu_type == DCERPC_PDU_TYPE__RESPONSE) || | (pdu_type == DCERPC_PDU_TYPE__RESPONSE) or | |||
(pdu_type == DCERPC_PDU_TYPE__FAULT) || | (pdu_type == DCERPC_PDU_TYPE__FAULT) or | |||
(pdu_type == DCERPC_PDU_TYPE__REJECT) || | (pdu_type == DCERPC_PDU_TYPE__REJECT) or | |||
(pdu_type == DCERPC_PDU_TYPE__FACK)) && | (pdu_type == DCERPC_PDU_TYPE__FACK)) and | |||
((cl_len != 0) && | ((cl_len != 0) and | |||
(cl_len + (unsigned)dcerpc_cl_hdr_len) <= len)) | (cl_len + (unsigned)dcerpc_cl_hdr_len) <= len) ) | |||
return true; | return true; | |||
} | } | |||
return false; | return false; | |||
} | } | |||
static bool dce_tcp_curse(const uint8_t* data, unsigned len, CurseTracker* track er) | static bool dce_tcp_curse(const uint8_t* data, unsigned len, CurseTracker* track er) | |||
{ | { | |||
const uint8_t dce_rpc_co_hdr_len = 16; | const uint8_t dce_rpc_co_hdr_len = 16; | |||
CurseTracker::DCE& dce = tracker->dce; | CurseTracker::DCE& dce = tracker->dce; | |||
uint32_t n = 0; | uint32_t n = 0; | |||
while (n < len) | while ( n < len ) | |||
{ | { | |||
switch (dce.state) | switch ( dce.state ) | |||
{ | { | |||
case STATE_0: // check major version | 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 | // go to bad state | |||
dce.state = STATE_10; | dce.state = STATE_10; | |||
return false; | return false; | |||
} | } | |||
dce.state = (DCE_State)((int)dce.state + 1); | dce.state = (DCE_State)((int)dce.state + 1); | |||
break; | break; | |||
case STATE_1: // check minor version | 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 | // go to bad state | |||
dce.state = STATE_10; | dce.state = STATE_10; | |||
return false; | return false; | |||
} | } | |||
dce.state = (DCE_State)((int)dce.state + 1); | dce.state = (DCE_State)((int)dce.state + 1); | |||
break; | break; | |||
case STATE_2: // pdu_type | case STATE_2: // pdu_type | |||
{ | { | |||
uint8_t pdu_type = data[n]; | 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 | // go to bad state | |||
dce.state = STATE_10; | dce.state = STATE_10; | |||
return false; | return false; | |||
} | } | |||
dce.state = (DCE_State)((int)dce.state + 1); | dce.state = (DCE_State)((int)dce.state + 1); | |||
break; | break; | |||
} | } | |||
case STATE_4: //little endian | case STATE_4: //little endian | |||
dce.helper = (data[n] & 0x10) << 20; | dce.helper = (data[n] & 0x10) << 20; | |||
dce.state = (DCE_State)((int)dce.state + 1); | dce.state = (DCE_State)((int)dce.state + 1); | |||
break; | break; | |||
case STATE_8: | case STATE_8: | |||
dce.helper |= data[n]; | dce.helper |= data[n]; | |||
dce.state = (DCE_State)((int)dce.state + 1); | dce.state = (DCE_State)((int)dce.state + 1); | |||
break; | break; | |||
case STATE_9: | case STATE_9: | |||
#ifdef WORDS_BIGENDIAN | #ifdef WORDS_BIGENDIAN | |||
if (!(dce.helper >> 24)) | if ( !(dce.helper >> 24) ) | |||
#else | #else | |||
if (dce.helper >> 24) | if ( dce.helper >> 24 ) | |||
#endif /* WORDS_BIGENDIAN */ | #endif /* WORDS_BIGENDIAN */ | |||
dce.helper = (data[n] << 8) | (dce.helper & 0XFF); | dce.helper = (data[n] << 8) | (dce.helper & 0XFF); | |||
else | else | |||
{ | { | |||
dce.helper <<=8; | dce.helper <<=8; | |||
dce.helper |= data[n]; | dce.helper |= data[n]; | |||
} | } | |||
if (dce.helper >= dce_rpc_co_hdr_len) | if ( dce.helper >= dce_rpc_co_hdr_len ) | |||
return true; | return true; | |||
dce.state = STATE_10; | dce.state = STATE_10; | |||
break; | break; | |||
case STATE_10: | case STATE_10: | |||
// no match | // no match | |||
return false; | return false; | |||
default: | default: | |||
dce.state = (DCE_State)((int)dce.state + 1); | dce.state = (DCE_State)((int)dce.state + 1); | |||
break; | break; | |||
} | } | |||
n++; | n++; | |||
} | } | |||
return false; | return false; | |||
} | } | |||
static bool dce_smb_curse(const uint8_t* data, unsigned len, CurseTracker* track er) | static bool dce_smb_curse(const uint8_t* data, unsigned len, CurseTracker* track er) | |||
{ | { | |||
const uint32_t dce_smb_id = 0xff534d42; /* \xffSMB */ | const uint32_t dce_smb_id = 0xff534d42; /* \xffSMB */ | |||
const uint32_t dce_smb2_id = 0xfe534d42; /* \xfeSMB */ | const uint32_t dce_smb2_id = 0xfe534d42; /* \xfeSMB */ | |||
const uint8_t session_request = 0x81, session_response = 0x82, | const uint8_t session_request = 0x81, session_response = 0x82, session_messa | |||
session_message = 0x00; | ge = 0x00; | |||
CurseTracker::DCE& dce = tracker->dce; | CurseTracker::DCE& dce = tracker->dce; | |||
uint32_t n = 0; | uint32_t n = 0; | |||
while (n < len) | while ( n < len ) | |||
{ | { | |||
switch (dce.state) | switch ( dce.state ) | |||
{ | { | |||
case STATE_0: | case STATE_0: | |||
if (data[n] == session_message) | if ( data[n] == session_message ) | |||
{ | { | |||
dce.state = (DCE_State)((int)dce.state + 2); | dce.state = (DCE_State)((int)dce.state + 2); | |||
break; | 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); | dce.state = (DCE_State)((int)dce.state + 1); | |||
return false; | return false; | |||
} | } | |||
dce.state = STATE_9; | dce.state = STATE_9; | |||
return false; | return false; | |||
case STATE_1: | case STATE_1: | |||
if (data[n] == session_message) | if ( data[n] == session_message ) | |||
{ | { | |||
dce.state = (DCE_State)((int)dce.state + 1); | dce.state = (DCE_State)((int)dce.state + 1); | |||
break; | break; | |||
} | } | |||
dce.state = STATE_9; | dce.state = STATE_9; | |||
return false; | return false; | |||
case STATE_5: | case STATE_5: | |||
dce.helper = data[n]; | dce.helper = data[n]; | |||
dce.state = (DCE_State)((int)dce.state + 1); | dce.state = (DCE_State)((int)dce.state + 1); | |||
break; | break; | |||
case STATE_6: | case STATE_6: | |||
case STATE_7: | case STATE_7: | |||
dce.helper <<= 8; | dce.helper <<= 8; | |||
dce.helper |= data[n]; | dce.helper |= data[n]; | |||
dce.state = (DCE_State)((int)dce.state + 1); | dce.state = (DCE_State)((int)dce.state + 1); | |||
break; | break; | |||
case STATE_8: | case STATE_8: | |||
dce.helper <<= 8; | dce.helper <<= 8; | |||
dce.helper |= data[n]; | 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; | return true; | |||
dce.state = (DCE_State)((int)dce.state + 1); | dce.state = (DCE_State)((int)dce.state + 1); | |||
break; | break; | |||
case STATE_9: | case STATE_9: | |||
// no match | // no match | |||
return false; | return false; | |||
default: | default: | |||
dce.state = (DCE_State)((int)dce.state + 1); | dce.state = (DCE_State)((int)dce.state + 1); | |||
break; | break; | |||
} | } | |||
n++; | n++; | |||
} | } | |||
return false; | return false; | |||
} | } | |||
static bool mms_curse(const uint8_t* data, unsigned len, CurseTracker* tracker) | static bool mms_curse(const uint8_t* data, unsigned len, CurseTracker* tracker) | |||
{ | { | |||
// peg the tracker to MMS | // peg the tracker to MMS | |||
CurseTracker::MMS& mms = tracker->mms; | CurseTracker::MMS& mms = tracker->mms; | |||
// if the state is set to MMS_STATE__SEARCH it means we most likely | // 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 | // have a split pipelined message coming through and will need to | |||
// reset the state | // reset the state | |||
if (mms.state == MMS_STATE__SEARCH) | if ( mms.state == MMS_STATE__SEARCH ) | |||
{ | { | |||
mms.state = mms.last_state; | mms.state = mms.last_state; | |||
} | } | |||
// define all known MMS tags to check for | // define all known MMS tags to check for | |||
enum | enum | |||
{ | { | |||
MMS_CONFIRMED_REQUEST_TAG = 0xA0, | MMS_CONFIRMED_REQUEST_TAG = 0xA0, | |||
MMS_CONFIRMED_RESPONSE_TAG = 0xA1, | MMS_CONFIRMED_RESPONSE_TAG = 0xA1, | |||
MMS_CONFIRMED_ERROR_TAG = 0xA2, | MMS_CONFIRMED_ERROR_TAG = 0xA2, | |||
skipping to change at line 297 | skipping to change at line 309 | |||
MMS_CANCEL_ERROR_TAG = 0xA7, | MMS_CANCEL_ERROR_TAG = 0xA7, | |||
MMS_INITIATE_REQUEST_TAG = 0xA8, | MMS_INITIATE_REQUEST_TAG = 0xA8, | |||
MMS_INITIATE_RESPONSE_TAG = 0xA9, | MMS_INITIATE_RESPONSE_TAG = 0xA9, | |||
MMS_INITIATE_ERROR_TAG = 0xAA, | MMS_INITIATE_ERROR_TAG = 0xAA, | |||
MMS_CONCLUDE_REQUEST_TAG = 0x8B, | MMS_CONCLUDE_REQUEST_TAG = 0x8B, | |||
MMS_CONCLUDE_RESPONSE_TAG = 0x8C, | MMS_CONCLUDE_RESPONSE_TAG = 0x8C, | |||
MMS_CONCLUDE_ERROR_TAG = 0xAD, | MMS_CONCLUDE_ERROR_TAG = 0xAD, | |||
}; | }; | |||
uint32_t idx = 0; | uint32_t idx = 0; | |||
while (idx < len) | while ( idx < len ) | |||
{ | { | |||
switch (mms.state) | switch ( mms.state ) | |||
{ | { | |||
case MMS_STATE__TPKT_VER: | case MMS_STATE__TPKT_VER: | |||
{ | { | |||
mms.state = MMS_STATE__TPKT_RES; | mms.state = MMS_STATE__TPKT_RES; | |||
break; | break; | |||
} | } | |||
case MMS_STATE__TPKT_RES: | case MMS_STATE__TPKT_RES: | |||
{ | { | |||
mms.state = MMS_STATE__TPKT_LEN1; | mms.state = MMS_STATE__TPKT_LEN1; | |||
skipping to change at line 338 | skipping to change at line 350 | |||
break; | break; | |||
} | } | |||
case MMS_STATE__COTP_PDU: | case MMS_STATE__COTP_PDU: | |||
{ | { | |||
// 7 6 5 4 3 2 1 0 | // 7 6 5 4 3 2 1 0 | |||
// --------------- | // --------------- | |||
// . . . . x x x x Destination Reference | // . . . . x x x x Destination Reference | |||
// x x x x . . . . PDU Type | // x x x x . . . . PDU Type | |||
const uint32_t MMS_COTP_PDU_DT_DATA = 0x0F; | 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; | mms.state = MMS_STATE__NOT_FOUND; | |||
break; | break; | |||
} | } | |||
mms.state = MMS_STATE__COTP_TPDU_NUM; | mms.state = MMS_STATE__COTP_TPDU_NUM; | |||
break; | break; | |||
} | } | |||
case MMS_STATE__COTP_TPDU_NUM: | case MMS_STATE__COTP_TPDU_NUM: | |||
{ | { | |||
mms.state = MMS_STATE__OSI_SESSION_SPDU; | mms.state = MMS_STATE__OSI_SESSION_SPDU; | |||
break; | break; | |||
} | } | |||
case MMS_STATE__OSI_SESSION_SPDU: | case MMS_STATE__OSI_SESSION_SPDU: | |||
{ | { | |||
// define all known OSI Session layer SPDU tags to check | // define all known OSI Session layer SPDU tags to check | |||
enum | enum | |||
{ | { | |||
MMS_OSI_SESSION_SPDU_GT_DT = 0x01, | MMS_OSI_SESSION_SPDU_GT_DT = 0x01, | |||
MMS_OSI_SESSION_SPDU_CN = 0x0D, | MMS_OSI_SESSION_SPDU_CN = 0x0D, | |||
MMS_OSI_SESSION_SPDU_AC = 0x0E, | MMS_OSI_SESSION_SPDU_AC = 0x0E, | |||
}; | }; | |||
switch (data[idx]) | switch ( data[idx] ) | |||
{ | { | |||
// check for a known MMS message tag in the event Session/Pr es/ACSE aren't used | // check for a known MMS message tag in the event Session/Pr es/ACSE aren't used | |||
case MMS_CONFIRMED_REQUEST_TAG: // fallthrough intentiona l | case MMS_CONFIRMED_REQUEST_TAG: // fallthrough intentiona l | |||
case MMS_CONFIRMED_RESPONSE_TAG: // fallthrough intentiona l | case MMS_CONFIRMED_RESPONSE_TAG: // fallthrough intentiona l | |||
case MMS_CONFIRMED_ERROR_TAG: // fallthrough intentiona l | case MMS_CONFIRMED_ERROR_TAG: // fallthrough intentiona l | |||
case MMS_UNCONFIRMED_TAG: // fallthrough intentiona l | case MMS_UNCONFIRMED_TAG: // fallthrough intentiona l | |||
case MMS_REJECT_TAG: // fallthrough intentiona l | case MMS_REJECT_TAG: // fallthrough intentiona l | |||
case MMS_CANCEL_REQUEST_TAG: // fallthrough intentiona l | case MMS_CANCEL_REQUEST_TAG: // fallthrough intentiona l | |||
case MMS_CANCEL_RESPONSE_TAG: // fallthrough intentiona l | case MMS_CANCEL_RESPONSE_TAG: // fallthrough intentiona l | |||
case MMS_CANCEL_ERROR_TAG: // fallthrough intentiona l | case MMS_CANCEL_ERROR_TAG: // fallthrough intentiona l | |||
skipping to change at line 409 | skipping to change at line 423 | |||
mms.state = MMS_STATE__NOT_FOUND; | mms.state = MMS_STATE__NOT_FOUND; | |||
} | } | |||
} | } | |||
break; | break; | |||
} | } | |||
case MMS_STATE__MMS: | case MMS_STATE__MMS: | |||
{ | { | |||
// loop through the remaining bytes in the buffer checking for k nown MMS tags | // loop through the remaining bytes in the buffer checking for k nown 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 know n tag map | // for each remaining byte check to see if it is in the know n tag map | |||
switch (data[i]) | switch ( data[i] ) | |||
{ | { | |||
case MMS_CONFIRMED_REQUEST_TAG: // fallthrough intent ional | case MMS_CONFIRMED_REQUEST_TAG: // fallthrough intent ional | |||
case MMS_CONFIRMED_RESPONSE_TAG: // fallthrough intent ional | case MMS_CONFIRMED_RESPONSE_TAG: // fallthrough intent ional | |||
case MMS_CONFIRMED_ERROR_TAG: // fallthrough intent ional | case MMS_CONFIRMED_ERROR_TAG: // fallthrough intent ional | |||
case MMS_UNCONFIRMED_TAG: // fallthrough intent ional | case MMS_UNCONFIRMED_TAG: // fallthrough intent ional | |||
case MMS_REJECT_TAG: // fallthrough intent ional | case MMS_REJECT_TAG: // fallthrough intent ional | |||
case MMS_CANCEL_REQUEST_TAG: // fallthrough intent ional | case MMS_CANCEL_REQUEST_TAG: // fallthrough intent ional | |||
case MMS_CANCEL_RESPONSE_TAG: // fallthrough intent ional | case MMS_CANCEL_RESPONSE_TAG: // fallthrough intent ional | |||
case MMS_CANCEL_ERROR_TAG: // fallthrough intent ional | case MMS_CANCEL_ERROR_TAG: // fallthrough intent ional | |||
case MMS_INITIATE_REQUEST_TAG: // fallthrough intent ional | case MMS_INITIATE_REQUEST_TAG: // fallthrough intent ional | |||
skipping to change at line 439 | skipping to change at line 453 | |||
// if an MMS tag exists in the remaining data, | // if an MMS tag exists in the remaining data, | |||
// hand off to the MMS service inspector | // hand off to the MMS service inspector | |||
mms.state = MMS_STATE__FOUND; | mms.state = MMS_STATE__FOUND; | |||
break; | break; | |||
} | } | |||
// no default here as it we don't know when we would hit | // no default here as it we don't know when we would hit | |||
// the first MMS tag without doing full parsing | // the first MMS tag without doing full parsing | |||
} | } | |||
// exit the loop when a state has been determined | // 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__SEARCH | |||
or mms.state == MMS_STATE__FOUND) | or mms.state == MMS_STATE__FOUND ) | |||
{ | { | |||
break; | break; | |||
} | } | |||
} | } | |||
break; | break; | |||
} | } | |||
case MMS_STATE__FOUND: | case MMS_STATE__FOUND: | |||
{ | { | |||
mms.state = MMS_STATE__TPKT_VER; | mms.state = MMS_STATE__TPKT_VER; | |||
return true; | return true; | |||
} | } | |||
case MMS_STATE__NOT_FOUND: | case MMS_STATE__NOT_FOUND: | |||
{ | { | |||
mms.state = MMS_STATE__TPKT_VER; | mms.state = MMS_STATE__TPKT_VER; | |||
return false; | return false; | |||
} | } | |||
default: | default: | |||
{ | { | |||
mms.state = MMS_STATE__NOT_FOUND; | mms.state = MMS_STATE__NOT_FOUND; | |||
assert(false); | assert(false); | |||
break; | break; | |||
} | } | |||
} | } | |||
idx++; | idx++; | |||
} | } | |||
mms.last_state = mms.state; | mms.last_state = mms.state; | |||
mms.state = MMS_STATE__SEARCH; | mms.state = MMS_STATE__SEARCH; | |||
return false; | return false; | |||
} | } | |||
namespace SSL_Const | namespace SSL_Const | |||
{ | { | |||
static constexpr uint8_t hdr_len = 9; | static constexpr uint8_t hdr_len = 9; | |||
static constexpr uint8_t sslv2_msb_set = 0x80; | static constexpr uint8_t sslv2_msb_set = 0x80; | |||
static constexpr uint8_t client_hello = 0x01; | static constexpr uint8_t client_hello = 0x01; | |||
static constexpr uint8_t sslv3_major_ver = 0x03; | static constexpr uint8_t sslv3_major_ver = 0x03; | |||
static constexpr uint8_t sslv3_max_minor_ver = 0x03; | static constexpr uint8_t sslv3_max_minor_ver = 0x03; | |||
} | } | |||
static bool ssl_v2_curse(const uint8_t* data, unsigned len, CurseTracker* tracke r) | static bool ssl_v2_curse(const uint8_t* data, unsigned len, CurseTracker* tracke r) | |||
{ | { | |||
CurseTracker::SSL& ssl = tracker->ssl; | CurseTracker::SSL& ssl = tracker->ssl; | |||
if (ssl.state == SSL_State::SSL_NOT_FOUND) | if ( ssl.state == SSL_State::SSL_NOT_FOUND ) | |||
{ | ||||
return false; | return false; | |||
} | else if ( ssl.state == SSL_State::SSL_FOUND ) | |||
else if (ssl.state == SSL_State::SSL_FOUND) | ||||
{ | ||||
return true; | return true; | |||
} | ||||
for (unsigned i = 0; i < len; ++i) | for ( unsigned i = 0; i < len; ++i ) | |||
{ | { | |||
uint8_t val = data[i]; | uint8_t val = data[i]; | |||
switch (ssl.state) | switch ( ssl.state ) | |||
{ | { | |||
case SSL_State::BYTE_0_LEN_MSB: | 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; | ssl.state = SSL_State::SSL_NOT_FOUND; | |||
return false; | return false; | |||
} | } | |||
ssl.total_len = (val & (~SSL_Const::sslv2_msb_set)) << 8; | ssl.total_len = (val & (~SSL_Const::sslv2_msb_set)) << 8; | |||
ssl.state = SSL_State::BYTE_1_LEN_LSB; | ssl.state = SSL_State::BYTE_1_LEN_LSB; | |||
break; | break; | |||
case SSL_State::BYTE_1_LEN_LSB: | case SSL_State::BYTE_1_LEN_LSB: | |||
ssl.total_len |= val; | 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; | ssl.state = SSL_State::SSL_NOT_FOUND; | |||
return false; | return false; | |||
} | } | |||
ssl.total_len -= SSL_Const::hdr_len; | ssl.total_len -= SSL_Const::hdr_len; | |||
ssl.state = SSL_State::BYTE_2_CLIENT_HELLO; | ssl.state = SSL_State::BYTE_2_CLIENT_HELLO; | |||
break; | break; | |||
case SSL_State::BYTE_2_CLIENT_HELLO: | 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; | ssl.state = SSL_State::SSL_NOT_FOUND; | |||
return false; | return false; | |||
} | } | |||
ssl.state = SSL_State::BYTE_3_MAX_MINOR_VER; | ssl.state = SSL_State::BYTE_3_MAX_MINOR_VER; | |||
break; | break; | |||
case SSL_State::BYTE_3_MAX_MINOR_VER: | 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; | ssl.state = SSL_State::SSL_NOT_FOUND; | |||
return false; | return false; | |||
} | } | |||
ssl.state = SSL_State::BYTE_4_V3_MAJOR; | ssl.state = SSL_State::BYTE_4_V3_MAJOR; | |||
break; | break; | |||
case SSL_State::BYTE_4_V3_MAJOR: | 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; | ssl.state = SSL_State::SSL_NOT_FOUND; | |||
return false; | return false; | |||
} | } | |||
ssl.state = SSL_State::BYTE_5_SPECS_LEN_MSB; | ssl.state = SSL_State::BYTE_5_SPECS_LEN_MSB; | |||
break; | break; | |||
case SSL_State::BYTE_5_SPECS_LEN_MSB: | case SSL_State::BYTE_5_SPECS_LEN_MSB: | |||
ssl.specs_len = val << 8; | ssl.specs_len = val << 8; | |||
ssl.state = SSL_State::BYTE_6_SPECS_LEN_LSB; | ssl.state = SSL_State::BYTE_6_SPECS_LEN_LSB; | |||
break; | break; | |||
case SSL_State::BYTE_6_SPECS_LEN_LSB: | case SSL_State::BYTE_6_SPECS_LEN_LSB: | |||
ssl.specs_len |= val; | 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; | ssl.state = SSL_State::SSL_NOT_FOUND; | |||
return false; | return false; | |||
} | } | |||
ssl.total_len -= ssl.specs_len; | ssl.total_len -= ssl.specs_len; | |||
ssl.state = SSL_State::BYTE_7_SSNID_LEN_MSB; | ssl.state = SSL_State::BYTE_7_SSNID_LEN_MSB; | |||
break; | break; | |||
case SSL_State::BYTE_7_SSNID_LEN_MSB: | case SSL_State::BYTE_7_SSNID_LEN_MSB: | |||
ssl.ssnid_len = val << 8; | ssl.ssnid_len = val << 8; | |||
ssl.state = SSL_State::BYTE_8_SSNID_LEN_LSB; | ssl.state = SSL_State::BYTE_8_SSNID_LEN_LSB; | |||
break; | break; | |||
case SSL_State::BYTE_8_SSNID_LEN_LSB: | case SSL_State::BYTE_8_SSNID_LEN_LSB: | |||
ssl.ssnid_len |= val; | 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; | ssl.state = SSL_State::SSL_NOT_FOUND; | |||
return false; | return false; | |||
} | } | |||
ssl.total_len -= ssl.ssnid_len; | ssl.total_len -= ssl.ssnid_len; | |||
ssl.state = SSL_State::BYTE_9_CHLNG_LEN_MSB; | ssl.state = SSL_State::BYTE_9_CHLNG_LEN_MSB; | |||
break; | break; | |||
case SSL_State::BYTE_9_CHLNG_LEN_MSB: | case SSL_State::BYTE_9_CHLNG_LEN_MSB: | |||
ssl.chlng_len = val << 8; | ssl.chlng_len = val << 8; | |||
ssl.state = SSL_State::BYTE_10_CHLNG_LEN_LSB; | ssl.state = SSL_State::BYTE_10_CHLNG_LEN_LSB; | |||
break; | break; | |||
case SSL_State::BYTE_10_CHLNG_LEN_LSB: | case SSL_State::BYTE_10_CHLNG_LEN_LSB: | |||
ssl.chlng_len |= val; | 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; | ssl.state = SSL_State::SSL_NOT_FOUND; | |||
return false; | return false; | |||
} | } | |||
ssl.state = SSL_State::SSL_FOUND; | ssl.state = SSL_State::SSL_FOUND; | |||
return true; | return true; | |||
default: | default: | |||
return false; | return false; | |||
} | } | |||
} | } | |||
return false; | return false; | |||
} | } | |||
skipping to change at line 620 | skipping to change at line 655 | |||
// name service alg is_tcp | // name service alg is_tcp | |||
{ "dce_udp", "dcerpc" , dce_udp_curse, false }, | { "dce_udp", "dcerpc" , dce_udp_curse, false }, | |||
{ "dce_tcp", "dcerpc" , dce_tcp_curse, true }, | { "dce_tcp", "dcerpc" , dce_tcp_curse, true }, | |||
{ "mms" , "mms" , mms_curse , true }, | { "mms" , "mms" , mms_curse , true }, | |||
{ "dce_smb", "netbios-ssn", dce_smb_curse, true }, | { "dce_smb", "netbios-ssn", dce_smb_curse, true }, | |||
{ "sslv2" , "ssl" , ssl_v2_curse , true } | { "sslv2" , "ssl" , ssl_v2_curse , true } | |||
}; | }; | |||
bool CurseBook::add_curse(const char* key) | 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); | tcp_curses.emplace_back(&curse); | |||
else | else | |||
non_tcp_curses.emplace_back(&curse); | non_tcp_curses.emplace_back(&curse); | |||
return true; | return true; | |||
} | } | |||
} | } | |||
return false; | return false; | |||
} | } | |||
const vector<const CurseDetails*>& CurseBook::get_curses(bool tcp) const | const vector<const CurseDetails*>& CurseBook::get_curses(bool tcp) const | |||
{ | { | |||
if (tcp) | if ( tcp ) | |||
return tcp_curses; | return tcp_curses; | |||
return non_tcp_curses; | return non_tcp_curses; | |||
} | } | |||
#ifdef CATCH_TEST_BUILD | #ifdef CATCH_TEST_BUILD | |||
#include "catch/catch.hpp" | #include "catch/catch.hpp" | |||
#include <cstring> | #include <cstring> | |||
//client hello with v2 header advertising sslv2 | //client hello with v2 header advertising sslv2 | |||
static const uint8_t ssl_v2_ch[] = | static const uint8_t ssl_v2_ch[] = | |||
skipping to change at line 672 | skipping to change at line 710 | |||
0xee,0xda,0xc1,0x9d,0xdc,0xd7,0xb8,0x86,0x51,0x10,0x5a }; | 0xee,0xda,0xc1,0x9d,0xdc,0xd7,0xb8,0x86,0x51,0x10,0x5a }; | |||
TEST_CASE("sslv2 detect", "[SslV2Curse]") | TEST_CASE("sslv2 detect", "[SslV2Curse]") | |||
{ | { | |||
uint32_t max_detect = static_cast<uint32_t>(SSL_State::BYTE_10_CHLNG_LEN_LSB ); | uint32_t max_detect = static_cast<uint32_t>(SSL_State::BYTE_10_CHLNG_LEN_LSB ); | |||
CurseTracker tracker{ }; | CurseTracker tracker{ }; | |||
auto test = [&](uint32_t incr_by,const uint8_t* ch) | auto test = [&](uint32_t incr_by,const uint8_t* ch) | |||
{ | { | |||
uint32_t i = 0; | 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(tracker.ssl.state == static_cast<SSL_State>(i)); | |||
CHECK_FALSE(ssl_v2_curse(&ch[i],sizeof(uint8_t) * incr_by,&t racker)); | CHECK_FALSE(ssl_v2_curse(&ch[i],sizeof(uint8_t) * incr_by,&t racker)); | |||
} | } | |||
else | else | |||
{ | { | |||
CHECK(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); | CHECK(tracker.ssl.state == SSL_State::SSL_FOUND); | |||
} | } | |||
i += incr_by; | i += incr_by; | |||
} | } | |||
//subsequent checks must return found | //subsequent checks must return found | |||
CHECK(ssl_v2_curse(&ch[max_detect + 1],sizeof(uint8_t),&tracker)); | CHECK(ssl_v2_curse(&ch[max_detect + 1],sizeof(uint8_t),&tracker)); | |||
CHECK(tracker.ssl.state == SSL_State::SSL_FOUND); | CHECK(tracker.ssl.state == SSL_State::SSL_FOUND); | |||
}; | }; | |||
//sslv2 with ssl version 2 | //sslv2 with ssl version 2 | |||
SECTION("1 byte v2"){ test(1,ssl_v2_ch); } | SECTION("1 byte v2"){ test(1,ssl_v2_ch); } | |||
SECTION("2 bytes v2"){ test(2,ssl_v2_ch); } | SECTION("2 bytes v2"){ test(2,ssl_v2_ch); } | |||
skipping to change at line 730 | skipping to change at line 769 | |||
uint32_t max_detect = static_cast<uint32_t>(SSL_State::BYTE_10_CHLNG_LEN_LSB ); | uint32_t max_detect = static_cast<uint32_t>(SSL_State::BYTE_10_CHLNG_LEN_LSB ); | |||
CurseTracker tracker{}; | CurseTracker tracker{}; | |||
uint8_t bad_data[] = {0x00,0x08,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff }; | uint8_t bad_data[] = {0x00,0x08,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff }; | |||
auto test = [&](uint32_t fail_at_byte) | auto test = [&](uint32_t fail_at_byte) | |||
{ | { | |||
uint8_t ch_data[sizeof(ssl_v2_ch)]; | uint8_t ch_data[sizeof(ssl_v2_ch)]; | |||
memcpy(ch_data,ssl_v2_ch,sizeof(ssl_v2_ch)); | memcpy(ch_data,ssl_v2_ch,sizeof(ssl_v2_ch)); | |||
ch_data[fail_at_byte] = bad_data[fail_at_byte]; | 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(tracker.ssl.state == static_cast<SSL_State>(i)); | |||
CHECK_FALSE(ssl_v2_curse(&ch_data[i],sizeof(uint8_t),&tracke r)); | CHECK_FALSE(ssl_v2_curse(&ch_data[i],sizeof(uint8_t),&tracke r)); | |||
} | } | |||
else | else | |||
{ | { | |||
CHECK_FALSE(ssl_v2_curse(&ch_data[i],sizeof(uint8_t),&tracke r)); | CHECK_FALSE(ssl_v2_curse(&ch_data[i],sizeof(uint8_t),&tracke r)); | |||
CHECK(tracker.ssl.state == SSL_State::SSL_NOT_FOUND); | CHECK(tracker.ssl.state == SSL_State::SSL_NOT_FOUND); | |||
} | } | |||
} | } | |||
End of changes. 87 change blocks. | ||||
61 lines changed or deleted | 101 lines changed or added |