/** * nntpplugin_LTX_ycIrcScanScan * * scans a given payload to see if it conforms to our idea of what NNTP traffic * looks like. * * * * @param argc NOT USED * @param argv NOT USED * @param payload pointer to the payload data * @param payloadSize the size of the payload parameter * @param flow a pointer to the flow state structure * @param val a pointer to biflow state (used for forward vs reverse) * * @return 0 for no match NNTP_PORT_NUMBER (119) for a match * */ uint16_t nntpplugin_LTX_ycNNTPScanScan ( int argc, char *argv[], uint8_t * payload, unsigned int payloadSize, yfFlow_t * flow, yfFlowVal_t * val) { int rc; # define NUM_CAPT_VECTS 60 int vects[NUM_CAPT_VECTS]; if (0 == pcreInitialized) { if (0 == ycNNTPScanInit()) { return 0; } } rc = pcre_exec(nntpCommandRegex, NULL, (char *)payload, payloadSize, 0, 0, vects, NUM_CAPT_VECTS); if (rc <= 0) { rc = pcre_exec(nntpResponseRegex, NULL, (char *)payload, payloadSize, 0, 0, vects, NUM_CAPT_VECTS); } /** at some point in the future, this is the place to extract protocol information like message targets and join targets, etc.*/ #if YAF_ENABLE_HOOKS if (rc > 0) { yfHookScanPayload(flow, payload, payloadSize, nntpCommandRegex, 0, 173, NNTP_PORT); yfHookScanPayload(flow, payload, payloadSize, nntpResponseRegex, 0, 172, NNTP_PORT); } #endif if (rc > 0) { return NNTP_PORT; } return 0; }
gboolean decodeTLSv1( uint8_t *payload, unsigned int payloadSize, yfFlow_t *flow, uint16_t offsetptr, uint16_t firstpkt, uint8_t datalength, uint8_t type) { uint32_t record_len; uint16_t header_len = offsetptr - 1; uint32_t cert_len, sub_cert_len; int cert_count = 0; uint16_t cipher_suite_len; uint8_t session_len; uint8_t compression_len; uint8_t next_msg; uint16_t ext_len = 0; uint16_t ext_ptr; uint16_t sub_ext_len; uint16_t sub_ext_type; /* Both Client and Server Hello's start off the same way */ /* 3 for Length, 2 for Version, 32 for Random, 1 for session ID Len*/ if (offsetptr + 39 > payloadSize) { return FALSE; } record_len = (ntohl(*(uint32_t *)(payload + offsetptr)) & 0xFFFFFF00) >> 8; offsetptr += 37; /* skip version & random*/ session_len = *(payload + offsetptr); offsetptr += session_len + 1; if (offsetptr + 2 > payloadSize){ return FALSE; } if (type == 1) { /* Client Hello */ cipher_suite_len = ntohs(*(uint16_t *)(payload + offsetptr)); /* figure out number of ciphers by dividing by 2 */ offsetptr += 2; if (cipher_suite_len > payloadSize) { return FALSE; } if (offsetptr + cipher_suite_len > payloadSize) { return FALSE; } /* cipher length */ /* ciphers are here */ offsetptr += cipher_suite_len; if (offsetptr + 1 > payloadSize) { return FALSE; } compression_len = *(payload + offsetptr); offsetptr += compression_len + 1; #if YAF_ENABLE_HOOKS yfHookScanPayload(flow, payload, cipher_suite_len, NULL, offsetptr+firstpkt, 91, TLS_PORT_NUMBER); #endif } else if (type == 2) { /* Server Hello */ if (offsetptr + 3 > payloadSize) { return FALSE; } /* cipher is here */ #if YAF_ENABLE_HOOKS yfHookScanPayload(flow, payload, 2, NULL, offsetptr+firstpkt, 89, TLS_PORT_NUMBER); #endif offsetptr += 2; /* compression method */ #if YAF_ENABLE_HOOKS yfHookScanPayload(flow, payload, 1, NULL, offsetptr+firstpkt, 90, TLS_PORT_NUMBER); #endif offsetptr++; } if ((offsetptr - header_len) < record_len) { int tot_ext = 0; /* extensions? */ ext_len = ntohs(*(uint16_t *)(payload + offsetptr)); ext_ptr = offsetptr + 2; offsetptr += ext_len + 2; #if YAF_ENABLE_HOOKS /* only want Client Hello's server name */ if (type == 1 && (offsetptr < payloadSize)) { while (ext_ptr < payloadSize && (tot_ext < ext_len)) { sub_ext_type = ntohs(*(uint16_t *)(payload + ext_ptr)); ext_ptr += 2; sub_ext_len = ntohs(*(uint16_t *)(payload + ext_ptr)); ext_ptr += 2; tot_ext += sizeof(uint16_t) + sizeof(uint16_t) + sub_ext_len; if (sub_ext_type != 0) { ext_ptr += sub_ext_len; continue; } if (sub_ext_len == 0) { /* no server name listed */ break; } /* grab server name */ /* jump past list length and type to get name length and name */ ext_ptr += 3; /* 2 for length, 1 for type */ sub_ext_len = ntohs(*(uint16_t *)(payload + ext_ptr)); ext_ptr += 2; if ((ext_ptr + sub_ext_len) < payloadSize) { yfHookScanPayload(flow, payload, sub_ext_len, NULL, ext_ptr+firstpkt, 95, TLS_PORT_NUMBER); } break; } } #endif } while (payloadSize > offsetptr) { next_msg = *(payload + offsetptr); if (next_msg == 11) { /* certificate */ if (offsetptr + 7 > payloadSize) { return TRUE; /* prob should be false */ } offsetptr++; record_len = (ntohl(*(uint32_t *)(payload + offsetptr)) & 0xFFFFFF00) >> 8; offsetptr += 3; /* Total Cert Length */ cert_len = (ntohl(*(uint32_t *)(payload + offsetptr)) & 0xFFFFFF00) >> 8; offsetptr += 3; while (payloadSize > (offsetptr + 4)) { sub_cert_len = (ntohl(*(uint32_t *)(payload + offsetptr)) & 0xFFFFFF00) >> 8; if ((sub_cert_len > cert_len) || (sub_cert_len < 2)) { /* it's at least got to have a version number */ return TRUE; /* prob should be false */ } else if (sub_cert_len > payloadSize) { /* just not enough room */ return TRUE; } /* offset of certificate */ if (cert_count < MAX_CERTS) { #if YAF_ENABLE_HOOKS if ((offsetptr + sub_cert_len + 3) < payloadSize) { yfHookScanPayload(flow, payload, 1, NULL, offsetptr+firstpkt, 93, TLS_PORT_NUMBER); } #endif } else { return TRUE; } cert_count++; offsetptr += 3 + sub_cert_len; } } else if (next_msg == 22) { /* 1 for type, 2 for version, 2 for length - we know it's long */ offsetptr += 5; } else if (next_msg == 20 || next_msg == 21 || next_msg == 23) { offsetptr += 3; /* 1 for type, 2 for version */ if ((offsetptr + 2) > payloadSize) { return TRUE; /* prob should be false */ } record_len = ntohs(*(uint16_t *)(payload + offsetptr)); if (record_len > payloadSize) { return TRUE; } offsetptr += record_len + 2; } else { return TRUE; } }
/** * proxyplugin_LTX_ycProxyScanScan * * the scanner for recognizing SSL/TLS packets through a proxy. * * @param argc number of string arguments in argv * @param argv string arguments for this plugin (first two are library * name and function name) * @param payload the packet payload * @param payloadSize size of the packet payload * @param flow a pointer to the flow state structure * @param val a pointer to biflow state (used for forward vs reverse) * * * @return TLS_PORT_NUMBER * otherwise 0 */ uint16_t proxyplugin_LTX_ycProxyScanScan ( int argc, char *argv[], uint8_t * payload, unsigned int payloadSize, yfFlow_t * flow, yfFlowVal_t * val) { #define NUM_CAPT_VECTS 60 int vects[NUM_CAPT_VECTS]; uint8_t ssl_length; uint8_t ssl_msgtype; uint16_t tls_version; uint16_t offsetptr = 0; uint16_t firstpkt = 0; unsigned int payloadLength = payloadSize; int rc, loop = 0; if (0 == pcreInitialized) { if (0 == yfProxyScanInit()) { return 0; } } /* if the applabel is 0, this is the fwd direction which should have * the HTTP CONNECT * * If not, we've probably already classified it as TLS and we're just * doing DPI */ if (flow->appLabel == 0) { rc = pcre_exec(httpConnectRegex, NULL, (char *)payload, payloadSize, 0, 0, vects, NUM_CAPT_VECTS); if (rc <= 0) { rc = pcre_exec(httpConnectEstRegex, NULL, (char *)payload, payloadSize, 0, 0, vects, NUM_CAPT_VECTS); if (rc <= 0) { return 0; } } } else if (flow->appLabel != TLS_PORT_NUMBER) { return 0; } /* every SSL/TLS header has to be at least 2 bytes long... */ if ( payloadSize < 45 ) { return 0; } while (loop < val->pkt && loop < YAF_MAX_PKT_BOUNDARY) { if (val->paybounds[loop] == 0) { loop++; } else { firstpkt = val->paybounds[loop]; break; } } /* http/1.0 connection established messaged is 39 bytes! */ payload += firstpkt; payloadLength -= firstpkt; /*understanding how to determine between SSLv2 and SSLv3/TLS is "borrowed" *from OpenSSL payload byte 0 for v2 is the start of the length field, but *its MSb is always reserved to tell us how long the length field is, and *in some cases, the second MSb is reserved as well */ /* when length is 2 bytes in size (MSb == 1), and the message type code is * 0x01 (client_hello) we know we're doing SSL v2 */ if ((payload[0] & 0x80) && (0x01 == payload[2])) { ssl_length = ((payload[0] & 0x7F) << 8) | payload[1]; if ( ssl_length < 2 ) { return 0; } ssl_msgtype = 1; offsetptr += 3; /* this is the version from the handshake message */ tls_version = ntohs(*(uint16_t *)(payload + offsetptr)); offsetptr += 2; if (tls_version == TLS_VERSION_1 || tls_version == SSL_VERSION_2 || tls_version == SSL_VERSION_3) { if ( !decodeSSLv2(payload, payloadLength, flow, offsetptr, firstpkt, ssl_length)) { return 0; } } else { return 0; } /* SSLv2 (client_hello) */ #if YAF_ENABLE_HOOKS yfHookScanPayload(flow, payload, 1, NULL, 41, 88, TLS_PORT_NUMBER); yfHookScanPayload(flow, payload, 2, NULL, tls_version, 94, TLS_PORT_NUMBER); #endif return TLS_PORT_NUMBER; } else { if ((0x00 == (payload[0] & 0x80)) && (0x00 == (payload[0] & 0x40)) && (0x01 == payload[3])) { /* this is ssl v2 but with a 3-byte header */ /* the second MSb means the record is a data record */ /* the fourth byte should be 1 for client hello */ if ((payload[0] == 0x16) && (payload[1] == 0x03)) { /* this is most likely tls, not sslv2 */ goto tls; } ssl_length = ((payload[0] * 0x3F) << 8) | payload[1]; if ( ssl_length < 3 ) { return 0; } offsetptr += 4; if ( (offsetptr + 2) < payloadLength ) { tls_version = ntohs(*(uint16_t *)(payload + offsetptr)); offsetptr += 2; if (tls_version == TLS_VERSION_1 || tls_version == SSL_VERSION_2 || tls_version == SSL_VERSION_3) { if (!decodeSSLv2(payload, payloadLength, flow, offsetptr, firstpkt, ssl_length)) { return 0; } } else { return 0; } } else { return 0; } #if YAF_ENABLE_HOOKS yfHookScanPayload(flow, payload, 1, NULL, 41, 88, TLS_PORT_NUMBER); yfHookScanPayload(flow, payload, 2, NULL, tls_version, 94, TLS_PORT_NUMBER); #endif return TLS_PORT_NUMBER; } tls: if ( payloadLength >= 10 ) { /* payload[0] is handshake request [0x16] payload[1] is ssl major version, sslv3 & tls is 3 payload[5] is handshake command, 1=client_hello,2=server_hello payload[3,4] is length payload[9] is the version from the record */ if ((payload[0] == 0x16) && (payload[1] == 0x03) && ((payload[5] == 0x01) || (payload[5] == 0x02)) && (((payload[3] == 0) && (payload[4] < 5)) || (payload[9] == payload[1]))) { ssl_msgtype = payload[5]; ssl_length = payload[4]; tls_version = ntohs(*(uint16_t *)(payload + 1)); /* 1 for content type, 2 for version, 2 for length, * 1 for handshake type*/ offsetptr += 6; /* now we should be at record length */ if (!decodeTLSv1(payload, payloadLength, flow, offsetptr, firstpkt, ssl_length, ssl_msgtype)) { return 0; } /* SSLv3 / TLS */ #if YAF_ENABLE_HOOKS yfHookScanPayload(flow, payload, 1, NULL, 42, 88, TLS_PORT_NUMBER); yfHookScanPayload(flow, payload, 2, NULL, tls_version, 94, TLS_PORT_NUMBER); #endif return TLS_PORT_NUMBER; } } } return 0; }