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; }
void oracle_classify(MolochSession_t *session, const unsigned char *data, int len, int which, void *UNUSED(uw)) { if (which != 0 || len <= 27 || len != data[1] || (data[25] + data[27] != len)) return; char *buf; // can't be more then 1 byte big int blen; buf = oracle_get_item((const char *)data, "HOST=", 5, &blen); if (buf && !moloch_field_string_add(hostField, session, buf, blen, FALSE)) { g_free(buf); } buf = oracle_get_item((const char *)data, "USER="******"SERVICE_NAME=", 13, &blen); if (buf && !moloch_field_string_add(serviceField, session, buf, blen, FALSE)) { g_free(buf); } moloch_session_add_protocol(session, "oracle"); }
void moloch_http_parse_authorization(MolochSession_t *session, char *str) { gsize olen; while (isspace(*str)) str++; char *space = strchr(str, ' '); if (!space) return; char *lower = g_ascii_strdown(str, space-str); if (!moloch_field_string_add(atField, session, lower, space-str, FALSE)) { g_free(lower); } if (strncasecmp("basic", str, 5) == 0) { str += 5; while (isspace(*str)) str++; // Yahoo reused Basic if (memcmp("token=", str, 6) != 0) { g_base64_decode_inplace(str, &olen); char *colon = strchr(str, ':'); if (colon) *colon = 0; moloch_field_string_add(userField, session, str, -1, TRUE); } } else if (strncasecmp("digest", str, 6) == 0) { str += 5; while (isspace(*str)) str++; char *username = strstr(str, "username"); if (!username) return; str = username + 8; while (isspace(*str)) str++; if (*str != '=') return; str++; // equal while (isspace(*str)) str++; int quote = 0; if (*str == '"') { quote = 1; str++; } char *end = str; while (*end && (*end != '"' || !quote) && (*end != ',' || quote)) { end++; } moloch_field_string_add(userField, session, str, end - str, TRUE); } }
LOCAL int irc_parser(MolochSession_t *session, void *uw, const unsigned char *data, int remaining, int which) { IRCInfo_t *irc = uw; if (which == 1) return 0; while (remaining) { if (irc->ircState & 0x1) { unsigned char *newline = memchr(data, '\n', remaining); if (newline) { irc->ircState &= ~ 0x1; remaining -= (newline - data) +1; data = newline+1; while (remaining > 0 && *data == 0) { // Some irc clients have 0's after new lines remaining--; data++; } } else { return 0; } } if (remaining > 5 && memcmp("JOIN ", data, 5) == 0) { const unsigned char *end = data + remaining; const unsigned char *ptr = data + 5; while (ptr < end && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') { ptr++; } moloch_field_string_add(channelsField, session, (char*)data + 5, ptr - data - 5, TRUE); } if (remaining > 5 && memcmp("NICK ", data, 5) == 0) { const unsigned char *end = data + remaining; const unsigned char *ptr = data + 5; while (ptr < end && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') { ptr++; } moloch_field_string_add(nickField, session, (char*)data + 5, ptr - data - 5, TRUE); } if (remaining > 0) { irc->ircState |= 0x1; } } return 0; }
LOCAL int quic_chlo_parser(MolochSession_t *session, BSB dbsb) { guchar *tag = 0; int tagLen = 0; BSB_LIMPORT_ptr(dbsb, tag, 4); BSB_LIMPORT_u16(dbsb, tagLen); BSB_LIMPORT_skip(dbsb, 2); if (BSB_IS_ERROR(dbsb)) { return 0; } moloch_session_add_protocol(session, "quic"); if (!tag || memcmp(tag, "CHLO", 4) != 0) { return 0; } guchar *tagDataStart = dbsb.buf + tagLen*8 + 8; uint32_t dlen = BSB_REMAINING(dbsb); uint32_t start = 0; while (!BSB_IS_ERROR(dbsb) && BSB_REMAINING(dbsb) && tagLen > 0) { guchar *subTag = 0; uint32_t endOffset = 0; BSB_LIMPORT_ptr(dbsb, subTag, 4); BSB_LIMPORT_u32(dbsb, endOffset); if (endOffset > dlen || start > dlen || start > endOffset) return 1; if (!subTag) return 1; if (memcmp(subTag, "SNI\x00", 4) == 0) { moloch_field_string_add(hostField, session, (char *)tagDataStart+start, endOffset-start, TRUE); } else if (memcmp(subTag, "UAID", 4) == 0) { moloch_field_string_add(uaField, session, (char *)tagDataStart+start, endOffset-start, TRUE); } else if (memcmp(subTag, "VER\x00", 4) == 0) { moloch_field_string_add(versionField, session, (char *)tagDataStart+start, endOffset-start, TRUE); } else { //LOG("Subtag: %4.4s len: %d %.*s", subTag, endOffset-start, endOffset-start, tagDataStart+start); } start = endOffset; tagLen--; } return 1; }
int irc_parser(MolochSession_t *session, void *uw, const unsigned char *data, int remaining) { IRCInfo_t *irc = uw; if (session->which == 1) return 0; while (remaining) { if (irc->ircState & 0x1) { unsigned char *newline = memchr(data, '\n', remaining); if (newline) { remaining -= (newline - data) +1; data = newline+1; irc->ircState &= ~ 0x1; } else { return 0; } } if (remaining > 5 && memcmp("JOIN ", data, 5) == 0) { const unsigned char *end = data + remaining; const unsigned char *ptr = data + 5; while (ptr < end && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') { ptr++; } moloch_field_string_add(MOLOCH_FIELD_IRC_CHANNELS, session, (char*)data + 5, ptr - data - 5, TRUE); } if (remaining > 5 && memcmp("NICK ", data, 5) == 0) { const unsigned char *end = data + remaining; const unsigned char *ptr = data + 5; while (ptr < end && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') { ptr++; } moloch_field_string_add(MOLOCH_FIELD_IRC_NICK, session, (char*)data + 5, ptr - data - 5, TRUE); } if (remaining > 0) { irc->ircState |= 0x1; } } return 0; }
/* wireshark: k5.asn which based on http://www.h5l.org/dist/src/heimdal-1.2.tar.gz --KDC-REQ-BODY ::= SEQUENCE { -- kdc-options[0] KDCOptions, -- cname[1] PrincipalName OPTIONAL, - - Used only in AS-REQ -- realm[2] Realm, - - Server's realm -- Also client's in AS-REQ -- sname[3] PrincipalName OPTIONAL, -- from[4] KerberosTime OPTIONAL, -- till[5] KerberosTime OPTIONAL, -- rtime[6] KerberosTime OPTIONAL, -- nonce[7] Krb5int32, -- etype[8] SEQUENCE OF ENCTYPE, - - EncryptionType, -- in preference order -- addresses[9] HostAddresses OPTIONAL, -- enc-authorization-data[10] EncryptedData OPTIONAL, -- Encrypted AuthorizationData encoding -- additional-tickets[11] SEQUENCE OF Ticket OPTIONAL --} */ LOCAL void krb5_parse_req_body(MolochSession_t *session, const unsigned char *data, int len) { MolochASNSeq_t seq[12]; int num = moloch_parsers_asn_get_sequence(seq, 12, data, len, TRUE); if (num < 2) return; int i; int vlen; const char *value; for (i = 0; i < num; i++) { switch (seq[i].tag) { case 1: krb5_parse_principal_name(session, cnameField, seq[i].value, seq[i].len); break; case 2: value = moloch_parsers_asn_sequence_to_string(&seq[i], &vlen); moloch_field_string_add(realmField, session, value, vlen, TRUE); break; case 3: krb5_parse_principal_name(session, snameField, seq[i].value, seq[i].len); break; } } }
void wise_process_ops(MolochSession_t *session, WiseItem_t *wi) { int i; for (i = 0; i < wi->numOps; i++) { WiseOp_t *op = &(wi->ops[i]); switch (config.fields[op->fieldPos]->type) { case MOLOCH_FIELD_TYPE_INT_HASH: if (op->fieldPos == tagsField) { moloch_nids_add_tag(session, op->str); continue; } // Fall Thru case MOLOCH_FIELD_TYPE_INT: case MOLOCH_FIELD_TYPE_INT_ARRAY: case MOLOCH_FIELD_TYPE_IP: case MOLOCH_FIELD_TYPE_IP_HASH: moloch_field_int_add(op->fieldPos, session, op->strLenOrInt); break; case MOLOCH_FIELD_TYPE_STR: case MOLOCH_FIELD_TYPE_STR_ARRAY: case MOLOCH_FIELD_TYPE_STR_HASH: moloch_field_string_add(op->fieldPos, session, op->str, op->strLenOrInt, TRUE); break; } } }
void http_add_value(MolochSession_t *session, HTTPInfo_t *http) { int pos = http->pos[session->which]; char *s = http->valueString[session->which]->str; int l = http->valueString[session->which]->len; while (isspace(*s)) { s++; l--; } switch (config.fields[pos]->type) { case MOLOCH_FIELD_TYPE_INT: case MOLOCH_FIELD_TYPE_INT_ARRAY: case MOLOCH_FIELD_TYPE_INT_HASH: moloch_field_int_add(pos, session, atoi(s)); g_string_free(http->valueString[session->which], TRUE); break; case MOLOCH_FIELD_TYPE_STR: case MOLOCH_FIELD_TYPE_STR_ARRAY: case MOLOCH_FIELD_TYPE_STR_HASH: moloch_field_string_add(pos, session, s, l, TRUE); g_string_free(http->valueString[session->which], TRUE); break; case MOLOCH_FIELD_TYPE_IP_HASH: { int i; gchar **parts = g_strsplit(http->valueString[session->which]->str, ",", 0); for (i = 0; parts[i]; i++) { gchar *ip = parts[i]; while (*ip == ' ') ip++; in_addr_t ia = inet_addr(ip); if (ia == 0 || ia == 0xffffffff) { moloch_nids_add_tag(session, "http:bad-xff"); LOG("ERROR - Didn't understand ip: %s %s %d", http->valueString[session->which]->str, ip, ia); continue; } moloch_field_int_add(pos, session, ia); } g_strfreev(parts); g_string_free(http->valueString[session->which], TRUE); break; } } /* SWITCH */ http->valueString[session->which] = 0; http->pos[session->which] = 0; }
void tls_process_server_hello(MolochSession_t *session, const unsigned char *data, int len) { BSB bsb; BSB_INIT(bsb, data, len); unsigned char *ver; BSB_IMPORT_ptr(bsb, ver, 2); BSB_IMPORT_skip(bsb, 32); // Random int skiplen = 0; BSB_IMPORT_u08(bsb, skiplen); // Session Id Length BSB_IMPORT_skip(bsb, skiplen); // Session Id unsigned char *cipher; BSB_IMPORT_ptr(bsb, cipher, 2); if (!BSB_IS_ERROR(bsb)) { char str[100]; if (ver[0] == 3) { switch (ver[1]) { case 0: moloch_field_string_add(verField, session, "SSLv3", 5, TRUE); break; case 1: moloch_field_string_add(verField, session, "TLSv1", 5, TRUE); break; case 2: moloch_field_string_add(verField, session, "TLSv1.1", 7, TRUE); break; case 3: moloch_field_string_add(verField, session, "TLSv1.2", 7, TRUE); break; default: snprintf(str, sizeof(str), "0x%02x.%02x", ver[0], ver[1]); moloch_field_string_add(verField, session, str, 6, TRUE); } } else { snprintf(str, sizeof(str), "0x%02x.%02x", ver[0], ver[1]); moloch_field_string_add(verField, session, str, 7, TRUE); } char *cipherStr = ciphers[cipher[0]][cipher[1]]; if (cipherStr) moloch_field_string_add(cipherField, session, cipherStr, -1, TRUE); else { snprintf(str, sizeof(str), "%02X%02X", cipher[0], cipher[1]); moloch_field_string_add(cipherField, session, str, 4, TRUE); } } }
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; }
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", session->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 << session->which) && http->pos[session->which]) { http_add_value(session, http); } if (pluginsCbs & MOLOCH_PLUGIN_HP_OHC) moloch_plugins_cb_hp_ohc(session, parser); return 0; }
void moloch_session_add_tag(MolochSession_t *session, const char *tag) { moloch_session_incr_outstanding(session); moloch_db_get_tag(session, config.tagsField, tag, moloch_session_get_tag_cb); moloch_field_string_add(config.tagsStringField, session, tag, -1, TRUE); if (session->stopSaving == 0 && HASH_COUNT(s_, config.dontSaveTags)) { MolochString_t *tstring; HASH_FIND(s_, config.dontSaveTags, tag, tstring); if (tstring) { session->stopSaving = (int)(long)tstring->uw; } } }
/* wireshark: k5.asn which based on http://www.h5l.org/dist/src/heimdal-1.2.tar.gz --PrincipalName ::= SEQUENCE { -- name-type[0] NAME-TYPE, -- name-string[1] SEQUENCE OF GeneralString --} */ LOCAL void krb5_parse_principal_name(MolochSession_t *session, int field, const unsigned char *data, int len) { MolochASNSeq_t seq[10]; int num = moloch_parsers_asn_get_sequence(seq, 2, data, len, TRUE); if (num < 2 || seq[1].tag != 1) return; num = moloch_parsers_asn_get_sequence(seq, 2, seq[1].value, seq[1].len, TRUE); int len0, len1; const char *value0, *value1; if (num == 1) { value0 = moloch_parsers_asn_sequence_to_string(&seq[0], &len0); moloch_field_string_add(field, session, value0, len0, TRUE); } else if (num == 2) { char str[255]; value0 = moloch_parsers_asn_sequence_to_string(&seq[0], &len0); value1 = moloch_parsers_asn_sequence_to_string(&seq[1], &len1); snprintf(str, 255, "%.*s/%.*s", len0, value0, len1, value1); moloch_field_string_add(field, session, str, len0 + 1 + len1, TRUE); } }
LOCAL int mysql_parser(MolochSession_t *session, void *uw, const unsigned char *data, int len, int which) { Info_t *info = uw; if (which != 0) { return 0; } if (info->ssl) { moloch_parsers_classify_tcp(session, data, len, which); moloch_parsers_unregister(session, info); return 0; } if (len < 35 || data[1] != 0 || data[2] != 0 || data[3] > 2) { 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_session_add_protocol(session, "mysql"); moloch_field_string_add(versionField, session, info->version, info->versionLen, FALSE); info->version = 0; if (ptr > data + 36) { moloch_field_string_add_lower(userField, session, (char*)data+36, ptr - (data + 36)); } if (data[5] & 0x08) { //CLIENT_SSL info->ssl = 1; } else { moloch_parsers_unregister(session, info); } 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", http->which); #endif if (pluginsCbs & MOLOCH_PLUGIN_HP_OMC) moloch_plugins_cb_hp_omc(session, parser); if (http->inBody & (1 << http->which)) { const char *md5 = g_checksum_get_string(http->checksum[http->which]); moloch_field_string_add(md5Field, session, (char*)md5, 32, TRUE); } return 0; }
static int MS_add_string(lua_State *L) { if (config.debug > 2) molua_stackDump(L); if (lua_gettop(L) != 3 || !lua_isuserdata(L, 1) || !(lua_isstring(L, 2) || lua_isinteger(L, 2)) || !lua_isstring(L, 3)) { return luaL_error(L, "usage: <session> <field string or field num(faster)> <string>"); } MolochSession_t *session = checkMolochSession(L, 1); const char *string = lua_tostring(L, 3); int len = lua_rawlen(L, 3); int pos; if (lua_isinteger(L, 2)) { pos = lua_tointeger(L, 2); } else { pos = moloch_field_by_exp(lua_tostring(L, 2)); } gboolean result; result = moloch_field_string_add(pos, session, string, len, TRUE); lua_pushboolean(L, result); return 1; }
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; }
void tls_process_client(MolochSession_t *session, const unsigned char *data, int len) { BSB sslbsb; BSB_INIT(sslbsb, data, len); if (BSB_REMAINING(sslbsb) > 5) { unsigned char *ssldata = BSB_WORK_PTR(sslbsb); int ssllen = MIN(BSB_REMAINING(sslbsb) - 5, ssldata[3] << 8 | ssldata[4]); BSB pbsb; BSB_INIT(pbsb, ssldata+5, ssllen); if (BSB_REMAINING(pbsb) > 7) { unsigned char *pdata = BSB_WORK_PTR(pbsb); int plen = MIN(BSB_REMAINING(pbsb) - 4, pdata[2] << 8 | pdata[3]); BSB cbsb; BSB_INIT(cbsb, pdata+6, plen-2); // The - 4 for plen is done above, confusing if(BSB_REMAINING(cbsb) > 32) { BSB_IMPORT_skip(cbsb, 32); // Random int skiplen = 0; BSB_IMPORT_u08(cbsb, skiplen); // Session Id Length BSB_IMPORT_skip(cbsb, skiplen); // Session Id BSB_IMPORT_u16(cbsb, skiplen); // Ciper Suites Length BSB_IMPORT_skip(cbsb, skiplen); // Ciper Suites BSB_IMPORT_u08(cbsb, skiplen); // Compression Length BSB_IMPORT_skip(cbsb, skiplen); // Compressions if (BSB_REMAINING(cbsb) > 2) { int etotlen = 0; BSB_IMPORT_u16(cbsb, etotlen); // Extensions Length etotlen = MIN(etotlen, BSB_REMAINING(cbsb)); BSB ebsb; BSB_INIT(ebsb, BSB_WORK_PTR(cbsb), etotlen); while (BSB_REMAINING(ebsb) > 0) { int etype = 0, elen = 0; BSB_IMPORT_u16 (ebsb, etype); BSB_IMPORT_u16 (ebsb, elen); if (etype != 0) { BSB_IMPORT_skip (ebsb, elen); continue; } if (elen > BSB_REMAINING(ebsb)) break; BSB snibsb; BSB_INIT(snibsb, BSB_WORK_PTR(ebsb), elen); BSB_IMPORT_skip (ebsb, elen); int sni = 0; BSB_IMPORT_u16(snibsb, sni); // list len if (sni != BSB_REMAINING(snibsb)) continue; BSB_IMPORT_u08(snibsb, sni); // type if (sni != 0) continue; BSB_IMPORT_u16(snibsb, sni); // len if (sni != BSB_REMAINING(snibsb)) continue; moloch_field_string_add(hostField, session, (char *)BSB_WORK_PTR(snibsb), sni, TRUE); } } } } BSB_IMPORT_skip(sslbsb, ssllen + 5); } }
void moloch_session_add_protocol(MolochSession_t *session, const char *protocol) { moloch_field_string_add(protocolField, session, protocol, -1, TRUE); }
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 radius_udp_parser(MolochSession_t *session, void *UNUSED(uw), const unsigned char *data, int len, int UNUSED(which)) { BSB bsb; BSB_INIT(bsb, data, len); BSB_IMPORT_skip(bsb, 20); unsigned char type = 0, length = 0; unsigned char *value; char str[256]; struct in_addr in; int i; while (BSB_REMAINING(bsb) > 2) { BSB_IMPORT_u08(bsb, type); BSB_IMPORT_u08(bsb, length); length -= 2; // length includes the type/length BSB_IMPORT_ptr(bsb, value, length); if (BSB_IS_ERROR(bsb)) { break; } switch (type) { case 1: moloch_field_string_add(userField, session, (char *)value, length, TRUE); break; /* case 4: LOG("NAS-IP-Address: %d %d %u.%u.%u.%u", type, length, value[0], value[1], value[2], value[3]); break;*/ case 8: memcpy(&in.s_addr, value, 4); moloch_field_int_add(framedIpField, session, in.s_addr); break; case 31: if (length == 12) { snprintf(str, sizeof(str), "%c%c:%c%c:%c%c:%c%c:%c%c:%c%c", value[0], value[1], value[2], value[3], value[4], value[5], value[6], value[7], value[8], value[9], value[10], value[11]); for (i = 0; i < 17; i++) { if (isupper (str[i])) str[i] = tolower (str[i]); } moloch_field_string_add(macField, session, str, 17, TRUE); } break; case 66: memcpy(str, value, length); str[length] = 0; inet_aton(str, &in); moloch_field_int_add(endpointIpField, session, in.s_addr); break; /* default: LOG("%d %d %.*s", type, length, length, value);*/ } } 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; }
// SSH Parsing currently assumes the parts we want from a SSH Packet will be // in a single TCP packet. Kind of sucks. int ssh_parser(MolochSession_t *session, void *uw, const unsigned char *data, int remaining, int which) { SSHInfo_t *ssh = uw; if (memcmp("SSH", data, 3) == 0) { unsigned char *n = memchr(data, 0x0a, remaining); if (n && *(n-1) == 0x0d) n--; if (n) { int len = (n - data); char *str = g_ascii_strdown((char *)data, len); if (!moloch_field_string_add(verField, session, str, len, FALSE)) { g_free(str); } } return 0; } if (which != 1) return 0; BSB bsb; BSB_INIT(bsb, data, remaining); while (BSB_REMAINING(bsb) > 6) { uint32_t loopRemaining = BSB_REMAINING(bsb); // If 0 looking for a ssh packet, otherwise in the middle of ssh packet if (ssh->sshLen == 0) { BSB_IMPORT_u32(bsb, ssh->sshLen); // Can't have a ssh packet > 35000 bytes. if (ssh->sshLen >= 35000) { moloch_parsers_unregister(session, uw); return 0; } ssh->sshLen += 4; uint8_t sshCode = 0; BSB_IMPORT_skip(bsb, 1); // padding length BSB_IMPORT_u08(bsb, sshCode); if (sshCode == 33) { moloch_parsers_unregister(session, uw); uint32_t keyLen = 0; BSB_IMPORT_u32(bsb, keyLen); if (!BSB_IS_ERROR(bsb) && BSB_REMAINING(bsb) >= keyLen) { char *str = g_base64_encode(BSB_WORK_PTR(bsb), keyLen); if (!moloch_field_string_add(keyField, session, str, (keyLen/3+1)*4, FALSE)) { g_free(str); } } break; } } if (loopRemaining > ssh->sshLen) { // Processed all, looking for another packet BSB_IMPORT_skip(bsb, loopRemaining); ssh->sshLen = 0; continue; } else { // Waiting on more data then in this callback ssh->sshLen -= loopRemaining; break; } } 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); } }