void other220_classify(MolochSession_t *session, const unsigned char *data, int len, int UNUSED(which)) { if (g_strstr_len((char *)data, len, "LMTP") != NULL) { moloch_nids_add_protocol(session, "lmtp"); } else if (g_strstr_len((char *)data, len, "SMTP") == NULL) { moloch_nids_add_protocol(session, "ftp"); } }
void gh0st_classify(MolochSession_t *session, const unsigned char *data, int len, int UNUSED(which)) { if (data[13] == 0x78 && (((data[8] == 0) && (data[7] == 0) && (((data[6]&0xff) << (uint32_t)8 | (data[5]&0xff)) == len)) || // Windows ((data[5] == 0) && (data[6] == 0) && (((data[7]&0xff) << (uint32_t)8 | (data[8]&0xff)) == len)))) { // Mac moloch_nids_add_protocol(session, "gh0st"); } if (data[7] == 0 && data[8] == 0 && data[11] == 0 && data[12] == 0 && data[13] == 0x78 && data[14] == 0x9c) { moloch_nids_add_protocol(session, "gh0st"); } }
void dns_tcp_classify(MolochSession_t *session, const unsigned char *UNUSED(data), int UNUSED(len), int which) { if (which == 0 && session->port2 == 53 && !moloch_nids_has_protocol(session, "dns")) { moloch_nids_add_protocol(session, "dns"); moloch_parsers_register(session, dns_tcp_parser, 0, 0); } }
void rdp_classify(MolochSession_t *session, const unsigned char *data, int len, int UNUSED(which)) { if (len > 5 && data[3] <= len && data[4] == (data[3] - 5) && data[5] == 0xe0) { moloch_nids_add_tag(session, "protocol:rdp"); moloch_nids_add_protocol(session, "rdp"); } }
void imap_classify(MolochSession_t *session, const unsigned char *data, int len, int UNUSED(which)) { if (moloch_memstr((const char *)data+5, len-5, "IMAP", 4)) { moloch_nids_add_tag(session, "protocol:imap"); moloch_nids_add_protocol(session, "imap"); } }
int mysql_parser(MolochSession_t *session, void *uw, const unsigned char *data, int len) { Info_t *info = uw; if (session->which != 0) { return 0; } if (len < 37 || data[1] != 0 || data[2] != 0 || data[3] != 1) { moloch_parsers_unregister(session, info); return 0; } unsigned char *ptr = (unsigned char*)data + 36; unsigned char *end = (unsigned char*)data + len; while (ptr < end) { if (*ptr == 0) break; if (!isprint(*ptr)) { moloch_parsers_unregister(session, info); return 0; } ptr++; } moloch_nids_add_protocol(session, "mysql"); moloch_field_string_add(versionField, session, info->version, info->versionLen, FALSE); info->version = 0; char *lower = g_ascii_strdown((char *)data+36, ptr - (data + 36)); moloch_field_string_add(userField, session, lower, ptr - (data + 36), FALSE); moloch_parsers_unregister(session, info); return 0; }
int socks4_parser(MolochSession_t *session, void *uw, const unsigned char *data, int remaining) { SocksInfo_t *socks = uw; switch(socks->state4) { case SOCKS4_STATE_REPLY: if (session->which == socks->which) return 0; if (remaining >= 8 && data[0] == 0 && data[1] >= 0x5a && data[1] <= 0x5d) { if (socks->ip) moloch_field_int_add(ipField, session, socks->ip); moloch_field_int_add(portField, session, socks->port); moloch_nids_add_tag(session, "protocol:socks"); moloch_nids_add_protocol(session, "socks"); if (socks->user) { if (!moloch_field_string_add(userField, session, socks->user, socks->userlen, FALSE)) { g_free(socks->user); } socks->user = 0; } if (socks->host) { if (!moloch_field_string_add(hostField, session, socks->host, socks->hostlen, FALSE)) { g_free(socks->host); } socks->host = 0; } moloch_parsers_classify_tcp(session, data+8, remaining-8); socks->state4 = SOCKS4_STATE_DATA; return 8; } break; case SOCKS4_STATE_DATA: if (session->which != socks->which) return 0; moloch_parsers_classify_tcp(session, data, remaining); moloch_parsers_unregister(session, uw); break; } return 0; }
void irc_classify(MolochSession_t *session, const unsigned char *data, int len, int which) { if (data[0] == ':' && !moloch_memstr((char *)data, len, " NOTICE ", 8)) return; //If a USER packet must have NICK with it so we don't pickup FTP if (data[0] == 'U' && !moloch_memstr((char *)data, len, "\nNICK ", 6)) { return; } if (moloch_nids_has_protocol(session, "irc")) return; moloch_nids_add_protocol(session, "irc"); IRCInfo_t *irc = MOLOCH_TYPE_ALLOC0(IRCInfo_t); moloch_parsers_register(session, irc_parser, irc, irc_free); irc_parser(session, irc, data, len, which); }
int socks5_parser(MolochSession_t *session, void *uw, const unsigned char *data, int remaining, int which) { SocksInfo_t *socks = uw; int consumed; //LOG("%d %d %d", which, socks->which, socks->state5[which]); //moloch_print_hex_string(data, remaining); switch(socks->state5[which]) { case SOCKS5_STATE_VER_REQUEST: if (data[2] == 0) { socks->state5[which] = SOCKS5_STATE_CONN_REQUEST; } else { socks->state5[which] = SOCKS5_STATE_USER_REQUEST; } socks->state5[(which+1)%2] = SOCKS5_STATE_VER_REPLY; break; case SOCKS5_STATE_VER_REPLY: if (remaining != 2 || data[0] != 5 || data[1] > 2) { moloch_parsers_unregister(session, uw); return 0; } moloch_nids_add_protocol(session, "socks"); if (socks->state5[socks->which] == SOCKS5_STATE_CONN_DATA) { // Other side of connection already in data state socks->state5[which] = SOCKS5_STATE_CONN_REPLY; } else if (data[1] == 0) { socks->state5[socks->which] = SOCKS5_STATE_CONN_REQUEST; socks->state5[which] = SOCKS5_STATE_CONN_REPLY; } else if (data[1] == 2) { socks->state5[socks->which] = SOCKS5_STATE_USER_REQUEST; socks->state5[which] = SOCKS5_STATE_USER_REPLY; } else { // We don't handle other auth methods moloch_parsers_unregister(session, uw); } return 2; case SOCKS5_STATE_USER_REQUEST: if ((2 + data[1] > (int)remaining) || (2 + data[1] + 1 + data[data[1]+2] > (int)remaining)) { moloch_parsers_unregister(session, uw); return 0; } moloch_field_string_add(userField, session, (char *)data + 2, data[1], TRUE); moloch_nids_add_tag(session, "socks:password"); socks->state5[which] = SOCKS5_STATE_CONN_REQUEST; return data[1] + 1 + data[data[1]+2]; case SOCKS5_STATE_USER_REPLY: socks->state5[which] = SOCKS5_STATE_CONN_REPLY; return 2; case SOCKS5_STATE_CONN_REQUEST: if (remaining < 6 || data[0] != 5 || data[1] != 1 || data[2] != 0) { moloch_parsers_unregister(session, uw); return 0; } socks->state5[which] = SOCKS5_STATE_CONN_DATA; if (data[3] == 1) { // IPV4 socks->port = (data[8]&0xff) << 8 | (data[9]&0xff); memcpy(&socks->ip, data+4, 4); moloch_field_int_add(ipField, session, socks->ip); moloch_field_int_add(portField, session, socks->port); consumed = 4 + 4 + 2; } else if (data[3] == 3) { // Domain Name socks->port = (data[5+data[4]]&0xff) << 8 | (data[6+data[4]]&0xff); char *lower = g_ascii_strdown((char*)data+5, data[4]); if (!moloch_field_string_add(hostField, session, lower, data[4], FALSE)) { g_free(lower); } moloch_field_int_add(portField, session, socks->port); consumed = 4 + 1 + data[4] + 2; } else if (data[3] == 4) { // IPV6 consumed = 4 + 16 + 2; } else { break; } moloch_parsers_classify_tcp(session, data+consumed, remaining-consumed, which); return consumed; case SOCKS5_STATE_CONN_REPLY: { if (remaining < 6) { moloch_parsers_unregister(session, uw); return 0; } socks->state5[which] = SOCKS5_STATE_CONN_DATA; if (data[3] == 1) { // IPV4 consumed = 4 + 4 + 2; } else if (data[3] == 3) { // Domain Name consumed = 4 + 1 + data[4] + 2; } else if (data[3] == 4) { // IPV6 consumed = 4 + 16 + 2; } else { break; } moloch_parsers_classify_tcp(session, data+consumed, remaining-consumed, which); return consumed; } case SOCKS5_STATE_CONN_DATA: moloch_parsers_classify_tcp(session, data, remaining, which); moloch_parsers_unregister(session, uw); return 0; default: moloch_parsers_unregister(session, uw); } return 0; }
int moloch_hp_cb_on_headers_complete (http_parser *parser) { HTTPInfo_t *http = parser->data; MolochSession_t *session = http->session; char tag[200]; char version[20]; #ifdef HTTPDEBUG LOG("HTTPDEBUG: which: %d code: %d method: %d", http->which, parser->status_code, parser->method); #endif int len = snprintf(version, sizeof(version), "%d.%d", parser->http_major, parser->http_minor); if (parser->status_code == 0) { #ifndef REMOVEOLD snprintf(tag, sizeof(tag), "http:method:%s", http_method_str(parser->method)); moloch_nids_add_tag(session, tag); #endif moloch_field_string_add(methodField, session, http_method_str(parser->method), -1, TRUE); moloch_field_string_add(verReqField, session, version, len, TRUE); } else { #ifndef REMOVEOLD snprintf(tag, sizeof(tag), "http:statuscode:%d", parser->status_code); moloch_nids_add_tag(session, tag); #endif moloch_field_int_add(statuscodeField, session, parser->status_code); moloch_field_string_add(verResField, session, version, len, TRUE); } if (http->inValue & (1 << http->which) && http->pos[http->which]) { http_add_value(session, http); } http->header[0][0] = http->header[1][0] = 0; if (http->urlString) { char *ch = http->urlString->str; while (*ch) { if (*ch < 32) { moloch_nids_add_tag(session, "http:control-char"); break; } ch++; } } if (http->cookieString && http->cookieString->str[0]) { char *start = http->cookieString->str; while (1) { while (isspace(*start)) start++; char *equal = strchr(start, '='); if (!equal) break; moloch_field_string_add(cookieKeyField, session, start, equal-start, TRUE); start = strchr(equal+1, ';'); if(!start) break; start++; } g_string_truncate(http->cookieString, 0); } if (http->authString && http->authString->str[0]) { moloch_http_parse_authorization(session, http->authString->str); g_string_truncate(http->authString, 0); } if (http->hostString) { g_string_ascii_down(http->hostString); } if (http->urlString && http->hostString) { char *colon = strchr(http->hostString->str+2, ':'); if (colon) { moloch_field_string_add(hostField, session, http->hostString->str+2, colon - http->hostString->str-2, TRUE); } else { moloch_field_string_add(hostField, session, http->hostString->str+2, http->hostString->len-2, TRUE); } char *question = strchr(http->urlString->str, '?'); if (question) { moloch_field_string_add(pathField, session, http->urlString->str, question - http->urlString->str, TRUE); char *start = question+1; char *ch; int field = keyField; for (ch = start; *ch; ch++) { if (*ch == '&') { if (ch != start && (config.parseQSValue || field == keyField)) { char *str = g_uri_unescape_segment(start, ch, NULL); if (!str) { moloch_field_string_add(field, session, start, ch-start, TRUE); } else if (!moloch_field_string_add(field, session, str, strlen(str), FALSE)) { g_free(str); } } start = ch+1; field = keyField; continue; } else if (*ch == '=') { if (ch != start && (config.parseQSValue || field == keyField)) { char *str = g_uri_unescape_segment(start, ch, NULL); if (!str) { moloch_field_string_add(field, session, start, ch-start, TRUE); } else if (!moloch_field_string_add(field, session, str, strlen(str), FALSE)) { g_free(str); } } start = ch+1; field = valueField; } } if (config.parseQSValue && field == valueField && ch > start) { char *str = g_uri_unescape_segment(start, ch, NULL); if (!str) { moloch_field_string_add(field, session, start, ch-start, TRUE); } else if (!moloch_field_string_add(field, session, str, strlen(str), FALSE)) { g_free(str); } } } else { moloch_field_string_add(pathField, session, http->urlString->str, http->urlString->len, TRUE); } if (http->urlString->str[0] != '/') { char *result = strstr(http->urlString->str, http->hostString->str+2); /* If the host header is in the first 8 bytes of url then just use the url */ if (result && result - http->urlString->str <= 8) { moloch_field_string_add(urlsField, session, http->urlString->str, http->urlString->len, FALSE); g_string_free(http->urlString, FALSE); g_string_free(http->hostString, TRUE); } else { /* Host header doesn't match the url */ g_string_append(http->hostString, ";"); g_string_append(http->hostString, http->urlString->str); moloch_field_string_add(urlsField, session, http->hostString->str, http->hostString->len, FALSE); g_string_free(http->urlString, TRUE); g_string_free(http->hostString, FALSE); } } else { /* Normal case, url starts with /, so no extra host in url */ g_string_append(http->hostString, http->urlString->str); moloch_field_string_add(urlsField, session, http->hostString->str, http->hostString->len, FALSE); g_string_free(http->urlString, TRUE); g_string_free(http->hostString, FALSE); } http->urlString = NULL; http->hostString = NULL; } else if (http->urlString) { moloch_field_string_add(urlsField, session, http->urlString->str, http->urlString->len, FALSE); g_string_free(http->urlString, FALSE); http->urlString = NULL; } else if (http->hostString) { char *colon = strchr(http->hostString->str+2, ':'); if (colon) { moloch_field_string_add(hostField, session, http->hostString->str+2, colon - http->hostString->str-2, TRUE); } else { moloch_field_string_add(hostField, session, http->hostString->str+2, http->hostString->len-2, TRUE); } g_string_free(http->hostString, TRUE); http->hostString = NULL; } moloch_nids_add_tag(session, "protocol:http"); moloch_nids_add_protocol(session, "http"); if (pluginsCbs & MOLOCH_PLUGIN_HP_OHC) moloch_plugins_cb_hp_ohc(session, parser); return 0; }
int moloch_hp_cb_on_message_complete (http_parser *parser) { HTTPInfo_t *http = parser->data; MolochSession_t *session = http->session; #ifdef HTTPDEBUG LOG("HTTPDEBUG: which: %d", session->which); #endif if (pluginsCbs & MOLOCH_PLUGIN_HP_OMC) moloch_plugins_cb_hp_omc(session, parser); http->header[0][0] = http->header[1][0] = 0; if (http->urlString) { char *ch = http->urlString->str; while (*ch) { if (*ch < 32) { moloch_nids_add_tag(session, "http:control-char"); break; } ch++; } } if (http->hostString) { g_string_ascii_down(http->hostString); } if (http->urlString && http->hostString) { char *colon = strchr(http->hostString->str+2, ':'); if (colon) { moloch_field_string_add(hostField, session, http->hostString->str+2, colon - http->hostString->str-2, TRUE); } else { moloch_field_string_add(hostField, session, http->hostString->str+2, http->hostString->len-2, TRUE); } char *question = strchr(http->urlString->str, '?'); if (question) { moloch_field_string_add(pathField, session, http->urlString->str, question - http->urlString->str, TRUE); char *start = question+1; char *ch; int field = keyField; for (ch = start; *ch; ch++) { if (*ch == '&') { if (ch != start && (config.parseQSValue || field == keyField)) { char *str = g_uri_unescape_segment(start, ch, NULL); if (!str) { moloch_field_string_add(field, session, start, ch-start, TRUE); } else if (!moloch_field_string_add(field, session, str, strlen(str), FALSE)) { g_free(str); } } start = ch+1; field = keyField; continue; } else if (*ch == '=') { if (ch != start && (config.parseQSValue || field == keyField)) { char *str = g_uri_unescape_segment(start, ch, NULL); if (!str) { moloch_field_string_add(field, session, start, ch-start, TRUE); } else if (!moloch_field_string_add(field, session, str, strlen(str), FALSE)) { g_free(str); } } start = ch+1; field = valueField; } } if (config.parseQSValue && field == valueField && ch > start) { char *str = g_uri_unescape_segment(start, ch, NULL); if (!str) { moloch_field_string_add(field, session, start, ch-start, TRUE); } else if (!moloch_field_string_add(field, session, str, strlen(str), FALSE)) { g_free(str); } } } else { moloch_field_string_add(pathField, session, http->urlString->str, http->urlString->len, TRUE); } if (http->urlString->str[0] != '/') { char *result = strstr(http->urlString->str, http->hostString->str+2); /* If the host header is in the first 8 bytes of url then just use the url */ if (result && result - http->urlString->str <= 8) { moloch_field_string_add(urlsField, session, http->urlString->str, http->urlString->len, FALSE); g_string_free(http->urlString, FALSE); g_string_free(http->hostString, TRUE); } else { /* Host header doesn't match the url */ g_string_append(http->hostString, ";"); g_string_append(http->hostString, http->urlString->str); moloch_field_string_add(urlsField, session, http->hostString->str, http->hostString->len, FALSE); g_string_free(http->urlString, TRUE); g_string_free(http->hostString, FALSE); } } else { /* Normal case, url starts with /, so no extra host in url */ g_string_append(http->hostString, http->urlString->str); moloch_field_string_add(urlsField, session, http->hostString->str, http->hostString->len, FALSE); g_string_free(http->urlString, TRUE); g_string_free(http->hostString, FALSE); } moloch_nids_add_tag(session, "protocol:http"); moloch_nids_add_protocol(session, "http"); http->urlString = NULL; http->hostString = NULL; } else if (http->urlString) { moloch_field_string_add(urlsField, session, http->urlString->str, http->urlString->len, FALSE); g_string_free(http->urlString, FALSE); moloch_nids_add_tag(session, "protocol:http"); moloch_nids_add_protocol(session, "http"); http->urlString = NULL; } else if (http->hostString) { char *colon = strchr(http->hostString->str+2, ':'); if (colon) { moloch_field_string_add(hostField, session, http->hostString->str+2, colon - http->hostString->str-2, TRUE); } else { moloch_field_string_add(hostField, session, http->hostString->str+2, http->hostString->len-2, TRUE); } g_string_free(http->hostString, TRUE); http->hostString = NULL; } if (http->inBody & (1 << session->which)) { const char *md5 = g_checksum_get_string(http->checksum[session->which]); moloch_field_string_add(md5Field, session, (char*)md5, 32, TRUE); } return 0; }
void dns_parser(MolochSession_t *session, const unsigned char *data, int len) { if (len < 18) return; int qr = (data[2] >> 7) & 0x1; int opcode = (data[2] >> 3) & 0xf; if (opcode != 0) return; int qdcount = (data[4] << 8) | data[5]; int ancount = (data[6] << 8) | data[7]; if (qdcount > 10 || qdcount <= 0) return; BSB bsb; BSB_INIT(bsb, data + 12, len - 12); /* QD Section */ int i; for (i = 0; BSB_NOT_ERROR(bsb) && i < qdcount; i++) { int namelen; unsigned char *name = dns_name(data, len, &bsb, &namelen); if (BSB_IS_ERROR(bsb)) break; if (!namelen) { name = (unsigned char*)"<root>"; namelen = 6; } unsigned short qtype = 0 , qclass = 0 ; BSB_IMPORT_u16(bsb, qtype); BSB_IMPORT_u16(bsb, qclass); char *lower = g_ascii_strdown((char*)name, namelen); if (qclass <= 255 && qclasses[qclass]) { moloch_field_string_add(queryClassField, session, qclasses[qclass], -1, TRUE); } if (qtype <= 255 && qtypes[qtype]) { moloch_field_string_add(queryTypeField, session, qtypes[qtype], -1, TRUE); } if (lower && !moloch_field_string_add(hostField, session, lower, namelen, FALSE)) { g_free(lower); } } moloch_nids_add_protocol(session, "dns"); if (qr == 0) return; int rcode = data[3] & 0xf; moloch_field_string_add(statusField, session, statuses[rcode], -1, TRUE); for (i = 0; BSB_NOT_ERROR(bsb) && i < ancount; i++) { int namelen; dns_name(data, len, &bsb, &namelen); if (BSB_IS_ERROR(bsb)) break; uint16_t antype = 0; BSB_IMPORT_u16 (bsb, antype); uint16_t anclass = 0; BSB_IMPORT_u16 (bsb, anclass); BSB_IMPORT_skip(bsb, 4); // ttl uint16_t rdlength = 0; BSB_IMPORT_u16 (bsb, rdlength); if (BSB_REMAINING(bsb) < rdlength) { break; } if (anclass != 1) { BSB_IMPORT_skip(bsb, rdlength); continue; } switch (antype) { case 1: { if (rdlength != 4) break; struct in_addr in; unsigned char *ptr = BSB_WORK_PTR(bsb); in.s_addr = ptr[3] << 24 | ptr[2] << 16 | ptr[1] << 8 | ptr[0]; moloch_field_int_add(ipField, session, in.s_addr); break; } case 5: { BSB rdbsb; BSB_INIT(rdbsb, BSB_WORK_PTR(bsb), rdlength); int namelen; unsigned char *name = dns_name(data, len, &rdbsb, &namelen); if (!namelen || BSB_IS_ERROR(rdbsb)) continue; char *lower = g_ascii_strdown((char*)name, namelen); if (lower && !moloch_field_string_add(hostField, session, lower, namelen, FALSE)) { g_free(lower); } break; } case 15: { BSB rdbsb; BSB_INIT(rdbsb, BSB_WORK_PTR(bsb), rdlength); BSB_IMPORT_skip(rdbsb, 2); // preference int namelen; unsigned char *name = dns_name(data, len, &rdbsb, &namelen); if (!namelen || BSB_IS_ERROR(rdbsb)) continue; char *lower = g_ascii_strdown((char*)name, namelen); if (lower && !moloch_field_string_add(hostField, session, lower, namelen, FALSE)) { g_free(lower); } } } /* switch */ BSB_IMPORT_skip(bsb, rdlength); } }
void vnc_classify(MolochSession_t *session, const unsigned char *data, int len, int UNUSED(which)) { if (len >= 12 && data[7] == '.' && data[11] == 0xa) moloch_nids_add_protocol(session, "vnc"); }
void pop3_classify(MolochSession_t *session, const unsigned char *UNUSED(data), int UNUSED(len), int UNUSED(which)) { moloch_nids_add_protocol(session, "pop3"); }
void bt_classify(MolochSession_t *session, const unsigned char *UNUSED(data), int UNUSED(len), int UNUSED(which)) { moloch_nids_add_tag(session, "protocol:bittorrent"); moloch_nids_add_protocol(session, "bittorrent"); }
void mongo_classify(MolochSession_t *session, const unsigned char *data, int len, int UNUSED(which)) { if (data[12] == 0xd4 && data[13] == 0x07 && g_strstr_len((gchar*)data+20, len-20, ".$cmd") != NULL) moloch_nids_add_protocol(session, "mongo"); }