service_netbios.cc (snort3-3.1.29.0) | : | service_netbios.cc (snort3-3.1.30.0) | ||
---|---|---|---|---|
skipping to change at line 27 | skipping to change at line 27 | |||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
//-------------------------------------------------------------------------- | //-------------------------------------------------------------------------- | |||
// service_netbios.cc author Sourcefire Inc. | // service_netbios.cc author Sourcefire Inc. | |||
#ifdef HAVE_CONFIG_H | #ifdef HAVE_CONFIG_H | |||
#include "config.h" | #include "config.h" | |||
#endif | #endif | |||
#include "service_netbios.h" | #include "service_netbios.h" | |||
#include "detection/detection_engine.h" | #include "detection/detection_engine.h" | |||
#include "protocols/packet.h" | #include "protocols/packet.h" | |||
#include "pub_sub/smb_events.h" | #include "pub_sub/smb_events.h" | |||
#include "utils/endian.h" | #include "utils/endian.h" | |||
#include "utils/util_cstring.h" | #include "utils/util_cstring.h" | |||
#include "app_info_table.h" | #include "app_info_table.h" | |||
#include "dcerpc.h" | #include "dcerpc.h" | |||
using namespace snort; | using namespace snort; | |||
#define NBSS_PORT 139 | #define NBNS_NB 32 | |||
#define NBNS_NBSTAT 33 | ||||
#define NBNS_NB 32 | #define NBNS_LENGTH_FLAGS 0xC0 | |||
#define NBNS_NBSTAT 33 | ||||
#define NBNS_LENGTH_FLAGS 0xC0 | ||||
#define NBNS_OPCODE_QUERY 0 | #define NBNS_OPCODE_QUERY 0 | |||
#define NBNS_OPCODE_REGISTRATION 5 | #define NBNS_OPCODE_REGISTRATION 5 | |||
#define NBNS_OPCODE_RELEASE 6 | #define NBNS_OPCODE_RELEASE 6 | |||
#define NBNS_OPCODE_WEACK 7 | #define NBNS_OPCODE_WEACK 7 | |||
#define NBNS_OPCODE_REFRESH 8 | #define NBNS_OPCODE_REFRESH 8 | |||
#define NBNS_OPCODE_REFRESHALT 9 | #define NBNS_OPCODE_REFRESHALT 9 | |||
#define NBNS_OPCODE_MHREGISTRATION 15 | #define NBNS_OPCODE_MHREGISTRATION 15 | |||
#define NBNS_REPLYCODE_MAX 7 | ||||
#define NBSS_COUNT_THRESHOLD 5 | ||||
#define NBNS_REPLYCODE_MAX 7 | ||||
#define NBSS_TYPE_MESSAGE 0x00 | ||||
#define NBSS_TYPE_REQUEST 0x81 | ||||
#define NBSS_TYPE_RESP_POSITIVE 0x82 | ||||
#define NBSS_TYPE_RESP_NEGATIVE 0x83 | ||||
#define NBSS_TYPE_RESP_RETARGET 0x84 | ||||
#define NBSS_TYPE_KEEP_ALIVE 0x85 | ||||
enum NBSSState | ||||
{ | ||||
NBSS_STATE_CONNECTION, | ||||
NBSS_STATE_FLOW, | ||||
NBSS_STATE_CONT, | ||||
NBSS_STATE_ERROR | ||||
}; | ||||
#define NBDGM_TYPE_DIRECT_UNIQUE 0x10 | #define NBDGM_TYPE_DIRECT_UNIQUE 0x10 | |||
#define NBDGM_TYPE_DIRECT_GROUP 0x11 | #define NBDGM_TYPE_DIRECT_GROUP 0x11 | |||
#define NBDGM_TYPE_BROADCAST 0x12 | #define NBDGM_TYPE_BROADCAST 0x12 | |||
#define NBDGM_TYPE_ERROR 0x13 | #define NBDGM_TYPE_ERROR 0x13 | |||
#define NBDGM_TYPE_REQUEST 0x14 | #define NBDGM_TYPE_REQUEST 0x14 | |||
#define NBDGM_TYPE_POSITIVE_REPSONSE 0x15 | #define NBDGM_TYPE_POSITIVE_REPSONSE 0x15 | |||
#define NBDGM_TYPE_NEGATIVE_RESPONSE 0x16 | #define NBDGM_TYPE_NEGATIVE_RESPONSE 0x16 | |||
#define NBDGM_ERROR_CODE_MIN 0x82 | ||||
#define NBDGM_ERROR_CODE_MIN 0x82 | #define NBDGM_ERROR_CODE_MAX 0x84 | |||
#define NBDGM_ERROR_CODE_MAX 0x84 | ||||
#define FINGERPRINT_UDP_FLAGS_XENIX 0x00000800 | #define FINGERPRINT_UDP_FLAGS_XENIX 0x00000800 | |||
#define FINGERPRINT_UDP_FLAGS_NT 0x00001000 | #define FINGERPRINT_UDP_FLAGS_NT 0x00001000 | |||
#define FINGERPRINT_UDP_FLAGS_MASK (FINGERPRINT_UDP_FLAGS_XENIX | FINGERPRINT_U DP_FLAGS_NT) | #define FINGERPRINT_UDP_FLAGS_MASK (FINGERPRINT_UDP_FLAGS_XENIX | FINGERPRINT_U DP_FLAGS_NT) | |||
#pragma pack(1) | #pragma pack(1) | |||
struct NBNSHeader | struct NBNSHeader | |||
{ | { | |||
uint16_t id; | uint16_t id; | |||
skipping to change at line 150 | skipping to change at line 127 | |||
uint8_t flag; | uint8_t flag; | |||
uint8_t position; | uint8_t position; | |||
}; | }; | |||
struct NBNSAnswerData | struct NBNSAnswerData | |||
{ | { | |||
uint32_t ttl; | uint32_t ttl; | |||
uint16_t data_len; | uint16_t data_len; | |||
}; | }; | |||
struct NBSSHeader | ||||
{ | ||||
uint8_t type; | ||||
uint8_t flags; | ||||
uint16_t length; | ||||
}; | ||||
uint8_t NB_SMB_BANNER[] = | uint8_t NB_SMB_BANNER[] = | |||
{ | { | |||
0xFF, 'S', 'M', 'B' | 0xFF, 'S', 'M', 'B' | |||
}; | }; | |||
uint8_t NB_SMB2_BANNER[] = | ||||
{ | ||||
0xFE, 'S', 'M', 'B' | ||||
}; | ||||
// this header is used in SMB3+ dialects for encryption negotiation | ||||
uint8_t NB_SMB2_TRANSFORM_BANNER[] = | ||||
{ | ||||
0xFD, 'S', 'M', 'B' | ||||
}; | ||||
struct ServiceSMBHeader | struct ServiceSMBHeader | |||
{ | { | |||
uint8_t command; | uint8_t command; | |||
uint32_t status; | uint32_t status; | |||
uint8_t flags[3]; | uint8_t flags[3]; | |||
uint16_t pid_high; | uint16_t pid_high; | |||
uint8_t signature[8]; | uint8_t signature[8]; | |||
uint16_t reserved2; | uint16_t reserved2; | |||
uint16_t tid; | uint16_t tid; | |||
uint16_t pid; | uint16_t pid; | |||
uint16_t uid; | uint16_t uid; | |||
uint16_t mid; | uint16_t mid; | |||
}; | }; | |||
struct ServiceSMB2Header | ||||
{ | ||||
uint16_t length; | ||||
uint16_t cc; | ||||
uint32_t status; | ||||
uint16_t command; | ||||
uint16_t cr; | ||||
uint32_t flags; | ||||
uint32_t nc; | ||||
uint32_t msg_id[2]; | ||||
uint32_t proc; | ||||
uint32_t tree_id; | ||||
uint32_t session_id[2]; | ||||
uint32_t sig[4]; | ||||
}; | ||||
struct ServiceSMB2SetupResponse | ||||
{ | ||||
uint16_t struct_size; | ||||
uint16_t flags; | ||||
uint16_t sec_offset; | ||||
uint16_t sec_length; | ||||
}; | ||||
struct ServiceSMB2NtlmChallenge | ||||
{ | ||||
uint8_t signature[8]; | ||||
uint32_t msg_type; | ||||
uint16_t target_name_len; | ||||
uint16_t target_name_max_len; | ||||
uint32_t target_name_offset; | ||||
uint32_t negotiate_flags; | ||||
uint8_t server_challenge[8]; | ||||
uint8_t reserved[8]; | ||||
uint16_t target_info_len; | ||||
uint16_t target_info_max_len; | ||||
uint32_t target_info_offset; | ||||
uint8_t version[8]; | ||||
}; | ||||
struct ServiceSMB2NtlmAttr | ||||
{ | ||||
uint16_t type; | ||||
uint16_t length; | ||||
}; | ||||
struct ServiceSMBAndXResponse | ||||
{ | ||||
uint8_t wc; | ||||
uint8_t cmd; | ||||
uint8_t reserved; | ||||
uint16_t offset; | ||||
uint16_t action; | ||||
uint16_t sec_len; | ||||
}; | ||||
struct ServiceSMBNegotiateProtocolResponse | ||||
{ | ||||
uint8_t wc; | ||||
uint16_t dialect_index; | ||||
uint8_t security_mode; | ||||
uint16_t max_mpx_count; | ||||
uint16_t max_vcs; | ||||
uint32_t max_buffer_size; | ||||
uint32_t max_raw_buffer; | ||||
uint32_t session_key; | ||||
uint32_t capabilities; | ||||
uint32_t system_time[2]; | ||||
uint16_t time_zone; | ||||
uint8_t sec_len; | ||||
}; | ||||
struct ServiceSMBTransactionHeader | struct ServiceSMBTransactionHeader | |||
{ | { | |||
uint8_t wc; | uint8_t wc; | |||
uint16_t total_pc; | uint16_t total_pc; | |||
uint16_t total_dc; | uint16_t total_dc; | |||
uint16_t max_pc; | uint16_t max_pc; | |||
uint16_t max_dc; | uint16_t max_dc; | |||
uint8_t max_sc; | uint8_t max_sc; | |||
uint8_t reserved; | uint8_t reserved; | |||
uint16_t flags; | uint16_t flags; | |||
uint32_t timeout; | uint32_t timeout; | |||
uint16_t reserved2; | uint16_t reserved2; | |||
uint16_t pc; | uint16_t pc; | |||
uint16_t po; | uint16_t po; | |||
uint16_t dc; | uint16_t dc; | |||
uint16_t offset; | uint16_t offset; | |||
uint8_t sc; | uint8_t sc; | |||
uint8_t reserved3; | uint8_t reserved3; | |||
}; | }; | |||
/* sc * 2 to get to the transaction name */ | ||||
#define SERVICE_SMB_STATUS_SUCCESS 0x00000000 | ||||
#define SERVICE_SMB_MORE_PROCESSING_REQUIRED 0xc0000016 | ||||
#define SERVICE_SMB_TRANSACTION_COMMAND 0x25 | ||||
#define SERVICE_SMB_COMMAND_SESSION_SETUP_ANDX_RESPONSE 0x73 | ||||
#define SERVICE_SMB_COMMAND_NEGOTIATE_PROTOCOL 0x72 | ||||
#define SERVICE_SMB_CAPABILITIES_EXTENDED_SECURITY 0x80000000 | ||||
#define SERVICE_SMB_CAPABILITIES_UNICODE 0x00000004 | ||||
#define SERVICE_SMB_FLAGS_RESPONSE 0x80 | ||||
#define SERVICE_SMB_FLAGS_UNICODE 0x80 | ||||
#define SERVICE_SMB_NOT_TRANSACTION_WC 8 | ||||
#define SERVICE_SMB_MAILSLOT_HOST 0x01 | ||||
#define SERVICE_SMB_MAILSLOT_LOCAL_MASTER 0x0f | ||||
#define SERVICE_SMB_MAILSLOT_SERVER_TYPE_XENIX 0x00000800 | ||||
#define SERVICE_SMB_MAILSLOT_SERVER_TYPE_NT 0x00001000 | ||||
#define SERVICE_SMB2_SESSION_SETUP 0x0001 | ||||
#define NTLM_CHALLENGE 0x00000002 | ||||
#define NTLM_DOMAIN_FLAG 0x0002 | ||||
static char mailslot[] = "\\MAILSLOT\\BROWSE"; | ||||
static char ntlmssp[] = "NTLMSSP"; | ||||
struct ServiceSMBBrowserHeader | struct ServiceSMBBrowserHeader | |||
{ | { | |||
uint8_t command; | uint8_t command; | |||
uint8_t count; | uint8_t count; | |||
uint32_t period; | uint32_t period; | |||
uint8_t hostname[16]; | uint8_t hostname[16]; | |||
uint8_t major; | uint8_t major; | |||
uint8_t minor; | uint8_t minor; | |||
uint32_t server_type; | uint32_t server_type; | |||
}; | }; | |||
struct ServiceNBSSData | #define SERVICE_SMB_TRANSACTION_COMMAND 0x25 | |||
{ | #define SERVICE_SMB_NOT_TRANSACTION_WC 8 | |||
NBSSState state; | #define SERVICE_SMB_MAILSLOT_HOST 0x01 | |||
unsigned count; | #define SERVICE_SMB_MAILSLOT_LOCAL_MASTER 0x0f | |||
uint32_t length; | static char mailslot[] = "\\MAILSLOT\\BROWSE"; | |||
AppId serviceAppId; | ||||
AppId miscAppId; | ||||
AppId payloadAppId; | ||||
}; | ||||
struct NBDgmHeader | struct NBDgmHeader | |||
{ | { | |||
uint8_t type; | uint8_t type; | |||
#if defined(WORDS_BIGENDIAN) | #if defined(WORDS_BIGENDIAN) | |||
uint8_t zero : 4, | uint8_t zero : 4, | |||
SNT : 2, | SNT : 2, | |||
first : 1, | first : 1, | |||
more : 1; | more : 1; | |||
#else | #else | |||
skipping to change at line 444 | skipping to change at line 306 | |||
if (lbl_data->len != NBNS_NAME_LEN) | if (lbl_data->len != NBNS_NAME_LEN) | |||
return -1; | return -1; | |||
if (lbl_data->zero) | if (lbl_data->zero) | |||
return -1; | return -1; | |||
for (i=0; i<NBNS_NAME_LEN; i++) | for (i=0; i<NBNS_NAME_LEN; i++) | |||
if (lbl_data->data[i] < 'A' or lbl_data->data[i] > 'Z') | if (lbl_data->data[i] < 'A' or lbl_data->data[i] > 'Z') | |||
return -1; | return -1; | |||
return 0; | return 0; | |||
} | } | |||
static int netbios_validate_label(const uint8_t** data, const uint8_t* const end | static int netbios_validate_label(const uint8_t** data, | |||
) | const uint8_t* const end) | |||
{ | { | |||
const NBNSLabel* lbl; | const NBNSLabel* lbl; | |||
uint16_t tmp; | uint16_t tmp; | |||
if (end - *data < (int)sizeof(NBNSLabel)) | if (end - *data < (int)sizeof(NBNSLabel)) | |||
return -1; | return -1; | |||
lbl = (const NBNSLabel*)(*data); | lbl = (const NBNSLabel*)(*data); | |||
*data += sizeof(NBNSLabel); | *data += sizeof(NBNSLabel); | |||
tmp = ntohs(lbl->type); | tmp = ntohs(lbl->type); | |||
if (tmp != NBNS_NB and tmp != NBNS_NBSTAT) | if (tmp != NBNS_NB and tmp != NBNS_NBSTAT) | |||
skipping to change at line 627 | skipping to change at line 490 | |||
fail: | fail: | |||
fail_service(args.asd, args.pkt, dir); | fail_service(args.asd, args.pkt, dir); | |||
return APPID_NOMATCH; | return APPID_NOMATCH; | |||
not_compatible: | not_compatible: | |||
incompatible_data(args.asd, args.pkt, dir); | incompatible_data(args.asd, args.pkt, dir); | |||
return APPID_NOT_COMPATIBLE; | return APPID_NOT_COMPATIBLE; | |||
} | } | |||
static void nbss_free_state(void* data) | ||||
{ | ||||
ServiceNBSSData* nd = (ServiceNBSSData*)data; | ||||
if (nd) | ||||
{ | ||||
snort_free(nd); | ||||
} | ||||
} | ||||
static inline void smb_domain_skip_string(const uint8_t** data, uint16_t* size, | ||||
uint16_t* offset, | ||||
const uint8_t unicode) | ||||
{ | ||||
if (unicode) | ||||
{ | ||||
if (*size != 0 and ((*offset) % 2)) | ||||
{ | ||||
(*offset)++; | ||||
(*data)++; | ||||
(*size)--; | ||||
} | ||||
while (*size > 1) | ||||
{ | ||||
*size -= 2; | ||||
*offset += 2; | ||||
if (**data == 0) | ||||
{ | ||||
*data += 2; | ||||
break; | ||||
} | ||||
else | ||||
{ | ||||
*data += 2; | ||||
} | ||||
} | ||||
} | ||||
else | ||||
{ | ||||
while (*size) | ||||
{ | ||||
(*size)--; | ||||
(*offset)++; | ||||
if (**data == 0) | ||||
{ | ||||
(*data)++; | ||||
break; | ||||
} | ||||
else | ||||
{ | ||||
(*data)++; | ||||
} | ||||
} | ||||
} | ||||
} | ||||
static void smb2_find_domain(const uint8_t* data, uint16_t size, | ||||
AppIdSession& asd, AppidChangeBits& change_bits) | ||||
{ | ||||
if (size < sizeof(ServiceSMB2Header)) | ||||
return; | ||||
const ServiceSMB2Header* smb2 = (const ServiceSMB2Header*)data; | ||||
if (smb2->command != SERVICE_SMB2_SESSION_SETUP) | ||||
return; | ||||
data += sizeof(*smb2); | ||||
size -= sizeof(*smb2); | ||||
if (size < sizeof(ServiceSMB2SetupResponse)) | ||||
return; | ||||
const ServiceSMB2SetupResponse* resp = (const ServiceSMB2SetupResponse*)data | ||||
; | ||||
if (resp->struct_size != 9 or resp->sec_length < 1) | ||||
return; | ||||
data += sizeof(*resp); | ||||
size -= sizeof(*resp); | ||||
if (size < resp->sec_length) | ||||
return; | ||||
const uint8_t* ptr = (const uint8_t*)SnortStrnStr((const char*)data, size, n | ||||
tlmssp); | ||||
if (!ptr) | ||||
return; | ||||
size -= ptr - data; | ||||
data = ptr; | ||||
if (size < sizeof(ServiceSMB2NtlmChallenge)) | ||||
return; | ||||
const ServiceSMB2NtlmChallenge* ntlm = (const ServiceSMB2NtlmChallenge*)data | ||||
; | ||||
if (ntlm->msg_type != NTLM_CHALLENGE) | ||||
return; | ||||
data += sizeof(*ntlm); | ||||
size -= sizeof(*ntlm); | ||||
if (size < ntlm->target_name_len or ntlm->target_name_len < 1 or ntlm->targe | ||||
t_info_len < 1) | ||||
return; | ||||
data += ntlm->target_name_len; | ||||
size -= ntlm->target_name_len; | ||||
const ServiceSMB2NtlmAttr* info; | ||||
while (true) | ||||
{ | ||||
if (size < sizeof(ServiceSMB2NtlmAttr)) | ||||
return; | ||||
info = (const ServiceSMB2NtlmAttr*)data; | ||||
data += sizeof(*info); | ||||
size -= sizeof(*info); | ||||
if (size < info->length or info->length == 0) | ||||
return; | ||||
if (info->type == NTLM_DOMAIN_FLAG) | ||||
break; | ||||
data += info->length; | ||||
size -= info->length; | ||||
} | ||||
char domain[NBNS_NAME_LEN+1]; | ||||
unsigned pos = 0; | ||||
while (pos < (info->length)/2 and pos < NBNS_NAME_LEN) | ||||
{ | ||||
domain[pos] = *data; | ||||
pos++; | ||||
domain[pos] = 0; | ||||
data++; | ||||
if (*data != 0) | ||||
return; | ||||
data++; | ||||
} | ||||
asd.set_netbios_domain(change_bits, (const char*)domain); | ||||
} | ||||
static void smb_find_domain(const uint8_t* data, uint16_t size, | ||||
AppIdSession& asd, AppidChangeBits& change_bits) | ||||
{ | ||||
const ServiceSMBHeader* smb; | ||||
const ServiceSMBAndXResponse* resp; | ||||
const ServiceSMBNegotiateProtocolResponse* np; | ||||
char domain[NBNS_NAME_LEN+1]; | ||||
unsigned pos = 0; | ||||
uint16_t byte_count; | ||||
uint16_t wc; | ||||
uint8_t unicode; | ||||
uint32_t capabilities; | ||||
uint16_t offset; | ||||
if (size < sizeof(*smb) + sizeof(wc)) | ||||
return; | ||||
smb = (const ServiceSMBHeader*)data; | ||||
if (smb->status != SERVICE_SMB_STATUS_SUCCESS and | ||||
smb->status != SERVICE_SMB_MORE_PROCESSING_REQUIRED) | ||||
return; | ||||
if (!(smb->flags[0] & SERVICE_SMB_FLAGS_RESPONSE)) | ||||
return; | ||||
unicode = smb->flags[2] & SERVICE_SMB_FLAGS_UNICODE; | ||||
data += sizeof(*smb); | ||||
size -= sizeof(*smb); | ||||
resp = (const ServiceSMBAndXResponse*)data; | ||||
np = (const ServiceSMBNegotiateProtocolResponse*)data; | ||||
wc = 2 * (uint16_t)*data; | ||||
offset = 0; | ||||
data++; | ||||
size--; | ||||
if (size < (wc + sizeof(byte_count))) | ||||
return; | ||||
data += wc; | ||||
size -= wc; | ||||
byte_count = LETOHS_UNALIGNED(data); | ||||
data += sizeof(byte_count); | ||||
size -= sizeof(byte_count); | ||||
if (size < byte_count) | ||||
return; | ||||
offset += sizeof(byte_count); | ||||
offset += wc; | ||||
if (smb->command == SERVICE_SMB_COMMAND_SESSION_SETUP_ANDX_RESPONSE) | ||||
{ | ||||
if (wc == 8) | ||||
{ | ||||
uint16_t sec_len = LETOHS_UNALIGNED(&resp->sec_len); | ||||
if (sec_len >= byte_count) | ||||
return; | ||||
data += sec_len; | ||||
byte_count -= sec_len; | ||||
} | ||||
else if (wc != 6) | ||||
return; | ||||
smb_domain_skip_string(&data, &byte_count, &offset, unicode); | ||||
smb_domain_skip_string(&data, &byte_count, &offset, unicode); | ||||
if (byte_count != 0 and (offset % 2)) | ||||
{ | ||||
data++; | ||||
byte_count--; | ||||
} | ||||
} | ||||
else if (smb->command == SERVICE_SMB_COMMAND_NEGOTIATE_PROTOCOL) | ||||
{ | ||||
if (wc == 34) | ||||
{ | ||||
capabilities = LETOHL_UNALIGNED(&np->capabilities); | ||||
if (capabilities & SERVICE_SMB_CAPABILITIES_EXTENDED_SECURITY) | ||||
return; | ||||
unicode = (capabilities & SERVICE_SMB_CAPABILITIES_UNICODE) or unico | ||||
de; | ||||
} | ||||
else if (wc != 26) | ||||
return; | ||||
if (np->sec_len >= byte_count) | ||||
return; | ||||
data += np->sec_len; | ||||
byte_count -= np->sec_len; | ||||
} | ||||
else | ||||
return; | ||||
if (unicode) | ||||
{ | ||||
int found = 0; | ||||
while (byte_count > 1) | ||||
{ | ||||
byte_count -= 2; | ||||
if (*data == 0) | ||||
{ | ||||
data += 2; | ||||
found = 1; | ||||
break; | ||||
} | ||||
else | ||||
{ | ||||
if (pos < NBNS_NAME_LEN) | ||||
{ | ||||
domain[pos] = *data; | ||||
pos++; | ||||
domain[pos] = 0; | ||||
} | ||||
data++; | ||||
if (*data != 0) | ||||
return; | ||||
data++; | ||||
} | ||||
} | ||||
if (!found and byte_count == 1 and *data == 0) | ||||
{ | ||||
byte_count--; | ||||
} | ||||
if (byte_count and smb->command != SERVICE_SMB_COMMAND_NEGOTIATE_PROTOCO | ||||
L and | ||||
smb->command != SERVICE_SMB_COMMAND_SESSION_SETUP_ANDX_RESPONSE) | ||||
return; | ||||
} | ||||
else | ||||
{ | ||||
while (byte_count) | ||||
{ | ||||
byte_count--; | ||||
if (*data == 0) | ||||
{ | ||||
data++; | ||||
break; | ||||
} | ||||
else | ||||
{ | ||||
if (pos < NBNS_NAME_LEN) | ||||
{ | ||||
domain[pos] = *data; | ||||
pos++; | ||||
domain[pos] = 0; | ||||
} | ||||
data++; | ||||
} | ||||
} | ||||
if (byte_count and smb->command != SERVICE_SMB_COMMAND_NEGOTIATE_PROTOCO | ||||
L) | ||||
return; | ||||
} | ||||
if (pos) | ||||
asd.set_netbios_domain(change_bits, (const char*)domain); | ||||
} | ||||
void NbssServiceDetector::parse_type_message(AppIdDiscoveryArgs& args, | ||||
const uint8_t* data, uint32_t tmp) | ||||
{ | ||||
ServiceNBSSData* nd = (ServiceNBSSData*)data_get(args.asd); | ||||
if (tmp >= sizeof(NB_SMB_BANNER) and | ||||
nd->length >= sizeof(NB_SMB_BANNER) and | ||||
!memcmp(data, NB_SMB_BANNER, sizeof(NB_SMB_BANNER))) | ||||
{ | ||||
if (nd->serviceAppId != APP_ID_DCE_RPC) | ||||
{ | ||||
nd->serviceAppId = APP_ID_NETBIOS_SSN; | ||||
nd->payloadAppId = APP_ID_SMB_VERSION_1; | ||||
} | ||||
if (nd->length <= tmp) | ||||
{ | ||||
smb_find_domain(data + sizeof(NB_SMB_BANNER), | ||||
tmp - sizeof(NB_SMB_BANNER), args.asd, args.change_bits); | ||||
} | ||||
} | ||||
else if (tmp >= sizeof(NB_SMB2_BANNER) and | ||||
nd->length >= sizeof(NB_SMB2_BANNER) and | ||||
!memcmp(data, NB_SMB2_BANNER, sizeof(NB_SMB2_BANNER))) | ||||
{ | ||||
if (nd->serviceAppId != APP_ID_DCE_RPC) | ||||
{ | ||||
nd->serviceAppId = APP_ID_NETBIOS_SSN; | ||||
nd->payloadAppId = APP_ID_SMB_VERSION_2; | ||||
} | ||||
if (nd->length <= tmp) | ||||
{ | ||||
smb2_find_domain(data + sizeof(NB_SMB2_BANNER), | ||||
tmp - sizeof(NB_SMB2_BANNER), args.asd, args.change_bits); | ||||
} | ||||
} | ||||
else if (tmp >= sizeof(NB_SMB2_TRANSFORM_BANNER) and | ||||
nd->length >= sizeof(NB_SMB2_TRANSFORM_BANNER) and | ||||
!memcmp(data, NB_SMB2_TRANSFORM_BANNER, sizeof(NB_SMB2_TRANSFORM_BANNER) | ||||
)) | ||||
{ | ||||
if (nd->serviceAppId != APP_ID_DCE_RPC) | ||||
{ | ||||
nd->serviceAppId = APP_ID_NETBIOS_SSN; | ||||
nd->payloadAppId = APP_ID_SMB_VERSION_3; | ||||
} | ||||
} | ||||
else if (tmp >= 4 and nd->length >= 4 and | ||||
!(*((const uint32_t*)data)) and | ||||
dcerpc_validate(data+4, ((int)std::min(tmp, nd->length)) - 4) > 0) | ||||
{ | ||||
nd->serviceAppId = APP_ID_DCE_RPC; | ||||
nd->miscAppId = APP_ID_NETBIOS_SSN; | ||||
} | ||||
} | ||||
NbssServiceDetector::NbssServiceDetector(ServiceDiscovery* sd) | ||||
{ | ||||
handler = sd; | ||||
name = "nbss"; | ||||
proto = IpProtocol::TCP; | ||||
detectorType = DETECTOR_TYPE_DECODER; | ||||
tcp_patterns = | ||||
{ | ||||
{ NB_SMB_BANNER, sizeof(NB_SMB_BANNER), -1, 0, 0 }, | ||||
{ NB_SMB2_BANNER, sizeof(NB_SMB2_BANNER), -1, 0, 0 }, | ||||
{ NB_SMB2_TRANSFORM_BANNER, sizeof(NB_SMB2_TRANSFORM_BANNER), -1, 0, 0 } | ||||
}; | ||||
appid_registry = | ||||
{ | ||||
{ APP_ID_NETBIOS_SSN, APPINFO_FLAG_SERVICE_ADDITIONAL }, | ||||
{ APP_ID_DCE_RPC, 0 } | ||||
}; | ||||
service_ports = | ||||
{ | ||||
{ 139, IpProtocol::TCP, false }, | ||||
{ 445, IpProtocol::TCP, false } | ||||
}; | ||||
handler->register_detector(name, this, proto); | ||||
} | ||||
int NbssServiceDetector::validate(AppIdDiscoveryArgs& args) | ||||
{ | ||||
ServiceNBSSData* nd; | ||||
const NBSSHeader* hdr; | ||||
const uint8_t* end; | ||||
uint32_t tmp; | ||||
int retval = -1; | ||||
const uint8_t* data = args.data; | ||||
const AppidSessionDirection dir = args.dir; | ||||
uint16_t size = args.size; | ||||
if (dir != APP_ID_FROM_RESPONDER) | ||||
goto inprocess; | ||||
if (!size) | ||||
goto inprocess; | ||||
nd = (ServiceNBSSData*)data_get(args.asd); | ||||
if (!nd) | ||||
{ | ||||
nd = (ServiceNBSSData*)snort_calloc(sizeof(ServiceNBSSData)); | ||||
data_add(args.asd, nd, &nbss_free_state); | ||||
nd->state = NBSS_STATE_CONNECTION; | ||||
nd->serviceAppId = APP_ID_NETBIOS_SSN; | ||||
nd->miscAppId = APP_ID_NONE; | ||||
} | ||||
end = data + size; | ||||
while (data < end) | ||||
{ | ||||
switch (nd->state) | ||||
{ | ||||
case NBSS_STATE_CONNECTION: | ||||
if (size < sizeof(NBSSHeader)) | ||||
goto fail; | ||||
hdr = (const NBSSHeader*)data; | ||||
data += sizeof(NBSSHeader); | ||||
nd->state = NBSS_STATE_ERROR; | ||||
switch (hdr->type) | ||||
{ | ||||
case NBSS_TYPE_RESP_POSITIVE: | ||||
if (hdr->flags or hdr->length) | ||||
goto fail; | ||||
nd->state = NBSS_STATE_FLOW; | ||||
break; | ||||
case NBSS_TYPE_RESP_NEGATIVE: | ||||
if (hdr->flags or ntohs(hdr->length) != 1) | ||||
goto fail; | ||||
if (data >= end) | ||||
goto fail; | ||||
if (*data < 0x80 or (*data > 0x83 and *data < 0x8F) or *data > 0 | ||||
x8F) | ||||
goto fail; | ||||
data++; | ||||
break; | ||||
case NBSS_TYPE_MESSAGE: | ||||
if (hdr->flags & 0xFE) | ||||
goto fail; | ||||
nd->length = ((uint32_t)(hdr->flags & 0x01)) << 16; | ||||
nd->length += (uint32_t)ntohs(hdr->length); | ||||
tmp = end - data; | ||||
parse_type_message(args, data, tmp); | ||||
if (tmp < nd->length) | ||||
{ | ||||
data = end; | ||||
nd->length -= tmp; | ||||
nd->state = NBSS_STATE_CONT; | ||||
} | ||||
else | ||||
{ | ||||
data += nd->length; | ||||
nd->count++; | ||||
nd->state = NBSS_STATE_FLOW; | ||||
retval = APPID_SUCCESS; | ||||
args.asd.set_session_flags(APPID_SESSION_CONTINUE); | ||||
} | ||||
break; | ||||
case NBSS_TYPE_RESP_RETARGET: | ||||
if (hdr->flags or ntohs(hdr->length) != 6) | ||||
goto fail; | ||||
if (end - data < 6) | ||||
goto fail; | ||||
data += 6; | ||||
break; | ||||
default: | ||||
goto fail; | ||||
} | ||||
break; | ||||
case NBSS_STATE_FLOW: | ||||
if (size < sizeof(NBSSHeader)) | ||||
goto fail; | ||||
hdr = (const NBSSHeader*)data; | ||||
data += sizeof(NBSSHeader); | ||||
switch (hdr->type) | ||||
{ | ||||
case NBSS_TYPE_KEEP_ALIVE: | ||||
if (hdr->flags or hdr->length) | ||||
goto fail; | ||||
break; | ||||
case NBSS_TYPE_MESSAGE: | ||||
if (hdr->flags & 0xFE) | ||||
goto fail; | ||||
nd->length = ((uint32_t)(hdr->flags & 0x01)) << 16; | ||||
nd->length += (uint32_t)ntohs(hdr->length); | ||||
tmp = end - data; | ||||
parse_type_message(args, data, tmp); | ||||
if (tmp < nd->length) | ||||
{ | ||||
data = end; | ||||
nd->length -= tmp; | ||||
nd->state = NBSS_STATE_CONT; | ||||
} | ||||
else | ||||
{ | ||||
data += nd->length; | ||||
if (nd->count < NBSS_COUNT_THRESHOLD) | ||||
{ | ||||
nd->count++; | ||||
retval = APPID_SUCCESS; | ||||
if (nd->count >= NBSS_COUNT_THRESHOLD) | ||||
args.asd.clear_session_flags(APPID_SESSION_CONTINUE) | ||||
; | ||||
else | ||||
args.asd.set_session_flags(APPID_SESSION_CONTINUE); | ||||
} | ||||
} | ||||
break; | ||||
default: | ||||
goto fail; | ||||
} | ||||
break; | ||||
case NBSS_STATE_CONT: | ||||
tmp = end - data; | ||||
if (tmp < nd->length) | ||||
{ | ||||
data = end; | ||||
nd->length -= tmp; | ||||
} | ||||
else | ||||
{ | ||||
data += nd->length; | ||||
nd->state = NBSS_STATE_FLOW; | ||||
if (nd->count < NBSS_COUNT_THRESHOLD) | ||||
{ | ||||
nd->count++; | ||||
retval = APPID_SUCCESS; | ||||
if (nd->count >= NBSS_COUNT_THRESHOLD) | ||||
args.asd.clear_session_flags(APPID_SESSION_CONTINUE); | ||||
else | ||||
args.asd.set_session_flags(APPID_SESSION_CONTINUE); | ||||
} | ||||
} | ||||
break; | ||||
default: | ||||
goto fail; | ||||
} | ||||
} | ||||
if (retval == -1) | ||||
goto inprocess; | ||||
if (!args.asd.is_service_detected()) | ||||
{ | ||||
if (add_service(args.change_bits, args.asd, args.pkt, dir, nd->serviceAp | ||||
pId) == APPID_SUCCESS) | ||||
{ | ||||
add_miscellaneous_info(args.asd, nd->miscAppId); | ||||
if (!args.asd.get_session_flags(APPID_SESSION_CONTINUE)) | ||||
add_payload(args.asd, nd->payloadAppId); | ||||
} | ||||
} | ||||
else if (!args.asd.get_session_flags(APPID_SESSION_CONTINUE)) | ||||
add_payload(args.asd, nd->payloadAppId); | ||||
return APPID_SUCCESS; | ||||
inprocess: | ||||
if (!args.asd.is_service_detected()) | ||||
service_inprocess(args.asd, args.pkt, dir); | ||||
return APPID_INPROCESS; | ||||
fail: | ||||
if (!args.asd.is_service_detected()) | ||||
fail_service(args.asd, args.pkt, dir); | ||||
return APPID_NOMATCH; | ||||
} | ||||
NbdgmServiceDetector::NbdgmServiceDetector(ServiceDiscovery* sd) | NbdgmServiceDetector::NbdgmServiceDetector(ServiceDiscovery* sd) | |||
{ | { | |||
handler = sd; | handler = sd; | |||
name = "nbdgm"; | name = "nbdgm"; | |||
proto = IpProtocol::UDP; | proto = IpProtocol::UDP; | |||
detectorType = DETECTOR_TYPE_DECODER; | detectorType = DETECTOR_TYPE_DECODER; | |||
appid_registry = | appid_registry = | |||
{ | { | |||
{ APP_ID_NETBIOS_DGM, APPINFO_FLAG_SERVICE_ADDITIONAL } | { APP_ID_NETBIOS_DGM, APPINFO_FLAG_SERVICE_ADDITIONAL } | |||
skipping to change at line 1286 | skipping to change at line 619 | |||
args.asd.set_netbios_name(args.change_bits, (const char*)source_name ); | args.asd.set_netbios_name(args.change_bits, (const char*)source_name ); | |||
args.asd.set_session_flags(APPID_SESSION_CONTINUE); | args.asd.set_session_flags(APPID_SESSION_CONTINUE); | |||
goto success; | goto success; | |||
case NBDGM_TYPE_ERROR: | case NBDGM_TYPE_ERROR: | |||
if (end-data < (int)sizeof(NBDgmError)) | if (end-data < (int)sizeof(NBDgmError)) | |||
goto fail; | goto fail; | |||
err = (const NBDgmError*)data; | err = (const NBDgmError*)data; | |||
data += sizeof(NBDgmError); | data += sizeof(NBDgmError); | |||
if (end != data) | if (end != data) | |||
goto fail; | goto fail; | |||
if (err->code < NBDGM_ERROR_CODE_MIN or | if (err->code < NBDGM_ERROR_CODE_MIN and | |||
err->code > NBDGM_ERROR_CODE_MAX) | err->code > NBDGM_ERROR_CODE_MAX) | |||
{ | { | |||
goto fail; | goto fail; | |||
} | } | |||
goto success; | goto success; | |||
default: | default: | |||
break; | break; | |||
} | } | |||
fail: | fail: | |||
End of changes. 12 change blocks. | ||||
694 lines changed or deleted | 14 lines changed or added |