int OS_DBSearchKeyAddressValue(ListRule *lrule, char *key) { int result=-1; char *val; unsigned vlen, vpos; if (lrule->db!= NULL) { if(_OS_CDBOpen(lrule->db) == -1) return 0; // First lookup for a single IP address if(cdb_find(&lrule->db->cdb, key, strlen(key)) > 0 ) { vpos = cdb_datapos(&lrule->db->cdb); vlen = cdb_datalen(&lrule->db->cdb); val = malloc(vlen); cdb_read(&lrule->db->cdb, val, vlen, vpos); result = OSMatch_Execute(val, vlen, lrule->matcher); free(val); return result; } else { // IP address not found, look for matching subnets char *tmpkey; os_strdup(key, tmpkey); while(strlen(tmpkey) > 0) { if(tmpkey[strlen(tmpkey) - 1] == '.') { if( cdb_find(&lrule->db->cdb, tmpkey, strlen(tmpkey)) > 0 ) { vpos = cdb_datapos(&lrule->db->cdb); vlen = cdb_datalen(&lrule->db->cdb); val = malloc(vlen); cdb_read(&lrule->db->cdb, val, vlen, vpos); result = OSMatch_Execute(val, vlen, lrule->matcher); free(val); free(tmpkey); return result; } } tmpkey[strlen(tmpkey) - 1] = '\0'; } free(tmpkey); return 0; } } return 0; }
/* Mark rules that match specific group (for if_matched_group) */ int OS_MarkGroup(RuleNode *r_node, RuleInfo *orig_rule) { /* If no r_node is given, get first node */ if(r_node == NULL) { r_node = OS_GetFirstRule(); } while(r_node) { if(OSMatch_Execute(r_node->ruleinfo->group, strlen(r_node->ruleinfo->group), orig_rule->if_matched_group)) { int rule_g = 0; if(r_node->ruleinfo->group_prev_matched) { while(r_node->ruleinfo->group_prev_matched[rule_g]) { rule_g++; } } os_realloc(r_node->ruleinfo->group_prev_matched, (rule_g + 2)*sizeof(OSList *), r_node->ruleinfo->group_prev_matched); r_node->ruleinfo->group_prev_matched[rule_g] = NULL; r_node->ruleinfo->group_prev_matched[rule_g +1] = NULL; /* Setting the size */ r_node->ruleinfo->group_prev_matched_sz = rule_g +1; r_node->ruleinfo->group_prev_matched[rule_g] = orig_rule->group_search; } /* Checking if the child has a rule */ if(r_node->child) { OS_MarkGroup(r_node->child, orig_rule); } r_node = r_node->next; } return(0); }
int OS_DBSearchKeyValue(ListRule *lrule, char *key) { int result=-1; char *val; unsigned vlen, vpos; if (lrule->db!= NULL) { if(_OS_CDBOpen(lrule->db) == -1) return 0; if(cdb_find(&lrule->db->cdb, key, strlen(key)) > 0 ) { vpos = cdb_datapos(&lrule->db->cdb); vlen = cdb_datalen(&lrule->db->cdb); val = malloc(vlen); cdb_read(&lrule->db->cdb, val, vlen, vpos); result = OSMatch_Execute(val, vlen, lrule->matcher); free(val); return result; } else { return 0; } } return 0; }
/* Read and generate the integrity data of a file */ static int read_file(const char *file_name, int opts, OSMatch *restriction) { char *buf; char sha1s = '+'; struct stat statbuf; /* Check if the file should be ignored */ if (syscheck.ignore) { int i = 0; while (syscheck.ignore[i] != NULL) { if (strncasecmp(syscheck.ignore[i], file_name, strlen(syscheck.ignore[i])) == 0) { return (0); } i++; } } /* Check in the regex entry */ if (syscheck.ignore_regex) { int i = 0; while (syscheck.ignore_regex[i] != NULL) { if (OSMatch_Execute(file_name, strlen(file_name), syscheck.ignore_regex[i])) { return (0); } i++; } } #ifdef WIN32 /* Win32 does not have lstat */ if (stat(file_name, &statbuf) < 0) #else if (lstat(file_name, &statbuf) < 0) #endif { if(errno == ENOTDIR){ /*Deletion message sending*/ char alert_msg[PATH_MAX+4]; alert_msg[PATH_MAX + 3] = '\0'; snprintf(alert_msg, PATH_MAX + 4, "-1 %s", file_name); send_syscheck_msg(alert_msg); return (0); }else{ merror("%s: Error accessing '%s'.", ARGV0, file_name); return (-1); } } if (S_ISDIR(statbuf.st_mode)) { #ifdef DEBUG verbose("%s: Reading dir: %s\n", ARGV0, file_name); #endif #ifdef WIN32 /* Directory links are not supported */ if (GetFileAttributes(file_name) & FILE_ATTRIBUTE_REPARSE_POINT) { merror("%s: WARN: Links are not supported: '%s'", ARGV0, file_name); return (-1); } #endif return (read_dir(file_name, opts, restriction)); } /* Restrict file types */ if (restriction) { if (!OSMatch_Execute(file_name, strlen(file_name), restriction)) { return (0); } } /* No S_ISLNK on Windows */ #ifdef WIN32 if (S_ISREG(statbuf.st_mode)) #else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode)) #endif { os_md5 mf_sum; os_sha1 sf_sum; os_sha1 sf_sum2; os_sha1 sf_sum3; /* Clean sums */ strncpy(mf_sum, "xxx", 4); strncpy(sf_sum, "xxx", 4); strncpy(sf_sum2, "xxx", 4); strncpy(sf_sum3, "xxx", 4); /* Generate checksums */ if ((opts & CHECK_MD5SUM) || (opts & CHECK_SHA1SUM)) { /* If it is a link, check if dest is valid */ #ifndef WIN32 if (S_ISLNK(statbuf.st_mode)) { struct stat statbuf_lnk; if (stat(file_name, &statbuf_lnk) == 0) { if (S_ISREG(statbuf_lnk.st_mode)) { if (OS_MD5_SHA1_File(file_name, syscheck.prefilter_cmd, mf_sum, sf_sum, OS_BINARY) < 0) { strncpy(mf_sum, "xxx", 4); strncpy(sf_sum, "xxx", 4); } } } } else if (OS_MD5_SHA1_File(file_name, syscheck.prefilter_cmd, mf_sum, sf_sum, OS_BINARY) < 0) #else if (OS_MD5_SHA1_File(file_name, syscheck.prefilter_cmd, mf_sum, sf_sum, OS_BINARY) < 0) #endif { strncpy(mf_sum, "xxx", 4); strncpy(sf_sum, "xxx", 4); } if (opts & CHECK_SEECHANGES) { sha1s = 's'; } } else { if (opts & CHECK_SEECHANGES) { sha1s = 'n'; } else { sha1s = '-'; } } buf = (char *) OSHash_Get(syscheck.fp, file_name); if (!buf) { char alert_msg[916 + 1]; /* to accommodate a long */ alert_msg[916] = '\0'; if (opts & CHECK_SEECHANGES) { char *alertdump = seechanges_addfile(file_name); if (alertdump) { free(alertdump); alertdump = NULL; } } snprintf(alert_msg, 916, "%c%c%c%c%c%c%c%c%ld:%d:%d:%d:%s:%s:%s:%s:%ld:%ld", opts & CHECK_SIZE ? '+' : '-', opts & CHECK_PERM ? '+' : '-', opts & CHECK_OWNER ? '+' : '-', opts & CHECK_GROUP ? '+' : '-', opts & CHECK_MD5SUM ? '+' : '-', sha1s, opts & CHECK_MTIME ? '+' : '-', opts & CHECK_INODE ? '+' : '-', opts & CHECK_SIZE ? (long)statbuf.st_size : 0, opts & CHECK_PERM ? (int)statbuf.st_mode : 0, opts & CHECK_OWNER ? (int)statbuf.st_uid : 0, opts & CHECK_GROUP ? (int)statbuf.st_gid : 0, opts & CHECK_MD5SUM ? mf_sum : "xxx", opts & CHECK_SHA1SUM ? sf_sum : "xxx", opts & CHECK_OWNER ? get_user(file_name, statbuf.st_uid) : "", opts & CHECK_GROUP ? get_group(statbuf.st_gid) : "", opts & CHECK_MTIME ? (long)statbuf.st_mtime : 0, opts & CHECK_INODE ? (long)statbuf.st_ino : 0); if (OSHash_Add(syscheck.fp, file_name, strdup(alert_msg)) <= 0) { merror("%s: ERROR: Unable to add file to db: %s", ARGV0, file_name); } /* Send the new checksum to the analysis server */ alert_msg[916] = '\0'; snprintf(alert_msg, 916, "%ld:%d:%d:%d:%s:%s:%s:%s:%ld:%ld %s", opts & CHECK_SIZE ? (long)statbuf.st_size : 0, opts & CHECK_PERM ? (int)statbuf.st_mode : 0, opts & CHECK_OWNER ? (int)statbuf.st_uid : 0, opts & CHECK_GROUP ? (int)statbuf.st_gid : 0, opts & CHECK_MD5SUM ? mf_sum : "xxx", opts & CHECK_SHA1SUM ? sf_sum : "xxx", opts & CHECK_OWNER ? get_user(file_name, statbuf.st_uid) : "", opts & CHECK_GROUP ? get_group(statbuf.st_gid) : "", opts & CHECK_MTIME ? (long)statbuf.st_mtime : 0, opts & CHECK_INODE ? (long)statbuf.st_ino : 0, file_name); send_syscheck_msg(alert_msg); } else { char alert_msg[OS_MAXSTR + 1]; char c_sum[256 + 2]; c_sum[0] = '\0'; c_sum[256] = '\0'; alert_msg[0] = '\0'; alert_msg[OS_MAXSTR] = '\0'; /* If it returns < 0, we have already alerted */ if (c_read_file(file_name, buf, c_sum) < 0) { return (0); } if (strcmp(c_sum, buf + 6) != 0) { /* Send the new checksum to the analysis server */ alert_msg[OS_MAXSTR] = '\0'; char *fullalert = NULL; if (buf[5] == 's' || buf[5] == 'n') { fullalert = seechanges_addfile(file_name); if (fullalert) { snprintf(alert_msg, OS_MAXSTR, "%s %s\n%s", c_sum, file_name, fullalert); free(fullalert); fullalert = NULL; } else { snprintf(alert_msg, 916, "%s %s", c_sum, file_name); } } else { snprintf(alert_msg, 916, "%s %s", c_sum, file_name); } send_syscheck_msg(alert_msg); } } /* Sleep here too */ if (__counter >= (syscheck.sleep_after)) { sleep(syscheck.tsleep); __counter = 0; } __counter++; #ifdef DEBUG verbose("%s: file '%s %s'", ARGV0, file_name, mf_sum); #endif } else { #ifdef DEBUG verbose("%s: *** IRREG file: '%s'\n", ARGV0, file_name); #endif } return (0); }
/* Receive a Message on the Mail queue */ MailMsg *OS_RecvMailQ(file_queue *fileq, struct tm *p, MailConfig *Mail, MailMsg **msg_sms) { int i = 0, sms_set = 0, donotgroup = 0; size_t body_size = OS_MAXSTR - 3, log_size; char logs[OS_MAXSTR + 1]; char extra_data[OS_MAXSTR + 1]; char log_string[OS_MAXSTR / 4 + 1]; char *subject_host; #ifdef LIBGEOIP_ENABLED char geoip_msg_src[OS_SIZE_1024 + 1]; char geoip_msg_dst[OS_SIZE_1024 + 1]; #endif MailMsg *mail; alert_data *al_data; Mail->priority = 0; /* Get message if available */ al_data = Read_FileMon(fileq, p, mail_timeout); if (!al_data) { return (NULL); } /* If e-mail came correctly, generate the e-mail body/subject */ os_calloc(1, sizeof(MailMsg), mail); os_calloc(BODY_SIZE, sizeof(char), mail->body); os_calloc(SUBJECT_SIZE, sizeof(char), mail->subject); /* Generate the logs */ logs[0] = '\0'; extra_data[0] = '\0'; logs[OS_MAXSTR] = '\0'; while (al_data->log[i]) { log_size = strlen(al_data->log[i]) + 4; /* If size left is small than the size of the log, stop it */ if (body_size <= log_size) { break; } strncat(logs, al_data->log[i], body_size); strncat(logs, "\r\n", body_size); body_size -= log_size; i++; } if (al_data->old_md5) { log_size = strlen(al_data->old_md5) + 16 + 4; if (body_size > log_size) { strncat(logs, "Old md5sum was: ", 16); strncat(logs, al_data->old_md5, body_size); strncat(logs, "\r\n", 4); body_size -= log_size; } } if (al_data->new_md5) { log_size = strlen(al_data->new_md5) + 16 + 4; if (body_size > log_size) { strncat(logs, "New md5sum is : ", 16); strncat(logs, al_data->new_md5, body_size); strncat(logs, "\r\n", 4); body_size -= log_size; } } if (al_data->old_sha1) { log_size = strlen(al_data->old_sha1) + 17 + 4; if (body_size > log_size) { strncat(logs, "Old sha1sum was: ", 17); strncat(logs, al_data->old_sha1, body_size); strncat(logs, "\r\n", 4); body_size -= log_size; } } if (al_data->new_sha1) { log_size = strlen(al_data->new_sha1) + 17 + 4; if (body_size > log_size) { strncat(logs, "New sha1sum is : ", 17); strncat(logs, al_data->new_sha1, body_size); strncat(logs, "\r\n", 4); body_size -= log_size; } } /* EXTRA DATA */ if (al_data->srcip) { log_size = snprintf(log_string, sizeof(log_string) - 1, "Src IP: %s\r\n", al_data->srcip ); if (body_size > log_size) { if ( strncat(extra_data, log_string, log_size) != NULL ) { body_size -= log_size; } } } if (al_data->dstip) { log_size = snprintf(log_string, sizeof(log_string) - 1, "Dst IP: %s\r\n", al_data->dstip ); if (body_size > log_size) { if ( strncat(extra_data, log_string, log_size) != NULL ) { body_size -= log_size; } } } if (al_data->user) { log_size = snprintf(log_string, sizeof(log_string) - 1, "User: %s\r\n", al_data->user ); if (body_size > log_size) { if ( strncat(extra_data, log_string, log_size) != NULL ) { body_size -= log_size; } } } /* Subject */ subject_host = strchr(al_data->location, '>'); if (subject_host) { subject_host--; *subject_host = '\0'; } /* We have two subject options - full and normal */ if (Mail->subject_full) { /* Option for a clean full subject (without ossec in the name) */ #ifdef CLEANFULL snprintf(mail->subject, SUBJECT_SIZE - 1, MAIL_SUBJECT_FULL2, al_data->level, al_data->comment, al_data->location); #else snprintf(mail->subject, SUBJECT_SIZE - 1, MAIL_SUBJECT_FULL, al_data->location, al_data->level, al_data->comment); #endif } else { snprintf(mail->subject, SUBJECT_SIZE - 1, MAIL_SUBJECT, al_data->location, al_data->level); } /* Fix subject back */ if (subject_host) { *subject_host = '-'; } #ifdef LIBGEOIP_ENABLED /* Get GeoIP information */ if (Mail->geoip) { if (al_data->srcgeoip) { snprintf(geoip_msg_src, OS_SIZE_1024, "Src Location: %s\r\n", al_data->srcgeoip); } else { geoip_msg_src[0] = '\0'; } if (al_data->dstgeoip) { snprintf(geoip_msg_dst, OS_SIZE_1024, "Dst Location: %s\r\n", al_data->dstgeoip); } else { geoip_msg_dst[0] = '\0'; } } else { geoip_msg_src[0] = '\0'; geoip_msg_dst[0] = '\0'; } #endif /* Body */ #ifdef LIBGEOIP_ENABLED snprintf(mail->body, BODY_SIZE - 1, MAIL_BODY, al_data->date, al_data->location, al_data->rule, al_data->level, al_data->comment, geoip_msg_src, geoip_msg_dst, extra_data, logs); #else snprintf(mail->body, BODY_SIZE - 1, MAIL_BODY, al_data->date, al_data->location, al_data->rule, al_data->level, al_data->comment, extra_data, logs); #endif debug2("OS_RecvMailQ: mail->body[%s]", mail->body); /* Check for granular email configs */ if (Mail->gran_to) { i = 0; while (Mail->gran_to[i] != NULL) { int gr_set = 0; /* Look if location is set */ if (Mail->gran_location[i]) { if (OSMatch_Execute(al_data->location, strlen(al_data->location), Mail->gran_location[i])) { gr_set = 1; } else { i++; continue; } } /* Look for the level */ if (Mail->gran_level[i]) { if (al_data->level >= Mail->gran_level[i]) { gr_set = 1; } else { i++; continue; } } /* Look for rule id */ if (Mail->gran_id[i]) { int id_i = 0; while (Mail->gran_id[i][id_i] != 0) { if (Mail->gran_id[i][id_i] == al_data->rule) { break; } id_i++; } /* If we found, id is going to be a valid rule */ if (Mail->gran_id[i][id_i]) { gr_set = 1; } else { i++; continue; } } /* Look for the group */ if (Mail->gran_group[i]) { if (OSMatch_Execute(al_data->group, strlen(al_data->group), Mail->gran_group[i])) { gr_set = 1; } else { i++; continue; } } /* If we got here, everything matched. Set this e-mail to be used. */ if (gr_set) { if (Mail->gran_format[i] == SMS_FORMAT) { Mail->gran_set[i] = SMS_FORMAT; /* Set the SMS flag */ sms_set = 1; } else { /* Options */ if (Mail->gran_format[i] == FORWARD_NOW) { Mail->priority = 1; Mail->gran_set[i] = FULL_FORMAT; } else if (Mail->gran_format[i] == DONOTGROUP) { Mail->priority = DONOTGROUP; Mail->gran_set[i] = DONOTGROUP; donotgroup = 1; } else { Mail->gran_set[i] = FULL_FORMAT; } } } i++; } } /* If DONOTGROUP is set, we can't assign the new subject */ if (!donotgroup) { /* Get highest level for alert */ if (_g_subject[0] != '\0') { if (_g_subject_level < al_data->level) { strncpy(_g_subject, mail->subject, SUBJECT_SIZE); _g_subject_level = al_data->level; } } else { strncpy(_g_subject, mail->subject, SUBJECT_SIZE); _g_subject_level = al_data->level; } } /* If SMS is set, create the SMS output */ if (sms_set) { MailMsg *msg_sms_tmp; /* Allocate memory for SMS */ os_calloc(1, sizeof(MailMsg), msg_sms_tmp); os_calloc(BODY_SIZE, sizeof(char), msg_sms_tmp->body); os_calloc(SUBJECT_SIZE, sizeof(char), msg_sms_tmp->subject); snprintf(msg_sms_tmp->subject, SUBJECT_SIZE - 1, SMS_SUBJECT, al_data->level, al_data->rule, al_data->comment); strncpy(msg_sms_tmp->body, logs, 128); msg_sms_tmp->body[127] = '\0'; *msg_sms = msg_sms_tmp; } /* Clear the memory */ FreeAlertData(al_data); return (mail); }
/** int OS_Alert_SendSyslog * Sends an alert via syslog. * Returns 1 on success or 0 on error. */ int OS_Alert_SendSyslog(alert_data *al_data, SyslogConfig *syslog_config) { char *tstamp; char syslog_msg[OS_SIZE_2048]; /* padding value */ int padding = 0; /* Invalid socket. */ if(syslog_config->socket < 0) { return(0); } /* Clearing the memory before insert */ memset(syslog_msg, '\0', OS_SIZE_2048); /* Looking if location is set */ if(syslog_config->location) { if(!OSMatch_Execute(al_data->location, strlen(al_data->location), syslog_config->location)) { return(0); } } /* Looking for the level */ if(syslog_config->level) { if(al_data->level < syslog_config->level) { return(0); } } /* Looking for rule id */ if(syslog_config->rule_id) { int id_i = 0; while(syslog_config->rule_id[id_i] != 0) { if(syslog_config->rule_id[id_i] == al_data->rule) { break; } id_i++; } /* If we found, id is going to be a valid rule */ if(!syslog_config->rule_id[id_i]) { return(0); } } /* Looking for the group */ if(syslog_config->group) { if(!OSMatch_Execute(al_data->group, strlen(al_data->group), syslog_config->group)) { return(0); } } /* Fixing the timestamp to be syslog compatible. * We have 2008 Jul 10 10:11:23 * Should be: Jul 10 10:11:23 */ tstamp = al_data->date; if(strlen(al_data->date) > 14) { tstamp+=5; /* Fixing first digit if the day is < 10 */ if(tstamp[4] == '0') tstamp[4] = ' '; } /* Inserting data */ if(syslog_config->format == DEFAULT_CSYSLOG) { /* Building syslog message. */ snprintf(syslog_msg, OS_SIZE_2048, "<%d>%s %s ossec: Alert Level: %d; Rule: %d - %s; Location: %s;", syslog_config->priority, tstamp, __shost, al_data->level, al_data->rule, al_data->comment, al_data->location ); field_add_string(syslog_msg, OS_SIZE_2048, " srcip: %s;", al_data->srcip ); #ifdef GEOIP field_add_string(syslog_msg, OS_SIZE_2048, " srccity: %s;", al_data->geoipdatasrc ); field_add_string(syslog_msg, OS_SIZE_2048, " dstcity: %s;", al_data->geoipdatadst ); #endif field_add_string(syslog_msg, OS_SIZE_2048, " dstip: %s;", al_data->dstip ); field_add_string(syslog_msg, OS_SIZE_2048, " user: %s;", al_data->user ); field_add_string(syslog_msg, OS_SIZE_2048, " Previous MD5: %s;", al_data->old_md5 ); field_add_string(syslog_msg, OS_SIZE_2048, " Current MD5: %s;", al_data->new_md5 ); field_add_string(syslog_msg, OS_SIZE_2048, " Previous SHA1: %s;", al_data->old_sha1 ); field_add_string(syslog_msg, OS_SIZE_2048, " Current SHA1: %s;", al_data->new_sha1 ); field_add_truncated(syslog_msg, OS_SIZE_2048, " %s", al_data->log[0], 2 ); } else if(syslog_config->format == CEF_CSYSLOG) { snprintf(syslog_msg, OS_SIZE_2048, "<%d>%s CEF:0|%s|%s|%s|%d|%s|%d|dvc=%s cs2=%s cs2Label=Location", syslog_config->priority, tstamp, __author, __ossec_name, __version, al_data->rule, al_data->comment, (al_data->level > 10) ? 10 : al_data->level, __shost, al_data->location); field_add_string(syslog_msg, OS_SIZE_2048, " src=%s", al_data->srcip ); field_add_string(syslog_msg, OS_SIZE_2048, " dpt=%s", al_data->dstport ); field_add_string(syslog_msg, OS_SIZE_2048, " spt=%s", al_data->srcport ); field_add_string(syslog_msg, OS_SIZE_2048, " fname=%s", al_data->filename ); field_add_string(syslog_msg, OS_SIZE_2048, " dhost=%s", al_data->dstip ); field_add_string(syslog_msg, OS_SIZE_2048, " shost=%s", al_data->srcip ); field_add_string(syslog_msg, OS_SIZE_2048, " suser=%s", al_data->user ); field_add_string(syslog_msg, OS_SIZE_2048, " dst=%s", al_data->dstip ); #ifdef GEOIP field_add_string(syslog_msg, OS_SIZE_2048, " cs3Label=SrcCity cs3=%s", al_data->geoipdatasrc ); field_add_string(syslog_msg, OS_SIZE_2048, " cs4Label=DstCity cs4=%s", al_data->geoipdatadst ); #endif field_add_string(syslog_msg, OS_SIZE_2048, " suser=%s", al_data->user ); field_add_string(syslog_msg, OS_SIZE_2048, " dst=%s", al_data->dstip ); field_add_truncated(syslog_msg, OS_SIZE_2048, " msg=%s", al_data->log[0], 2 ); if (al_data->new_md5 && al_data->new_sha1) { field_add_string(syslog_msg, OS_SIZE_2048, " cs1Label=OldMD5 cs1=%s", al_data->old_md5); field_add_string(syslog_msg, OS_SIZE_2048, " cs2Label=NewMDG cs2=%s", al_data->new_md5); field_add_string(syslog_msg, OS_SIZE_2048, " oldFileHash=%s", al_data->old_sha1 ); field_add_string(syslog_msg, OS_SIZE_2048, " fhash=%s", al_data->new_sha1 ); field_add_string(syslog_msg, OS_SIZE_2048, " fileHash=%s", al_data->new_sha1 ); } } else if(syslog_config->format == JSON_CSYSLOG) { /* Build a JSON Object for logging */ cJSON *root; char *json_string; root = cJSON_CreateObject(); // Data guaranteed to be there cJSON_AddNumberToObject(root, "crit", al_data->level); cJSON_AddNumberToObject(root, "id", al_data->rule); cJSON_AddStringToObject(root, "component", al_data->location); // Rule Meta Data if (al_data->group) cJSON_AddStringToObject(root, "classification", al_data->group); if (al_data->comment) cJSON_AddStringToObject(root, "description", al_data->comment); // Raw log message generating event if (al_data->log && al_data->log[0]) cJSON_AddStringToObject(root, "message", al_data->log[0]); // Add data if it exists if (al_data->user) cJSON_AddStringToObject(root, "acct", al_data->user); if (al_data->srcip) cJSON_AddStringToObject(root, "src_ip", al_data->srcip); if (al_data->srcport) cJSON_AddNumberToObject(root, "src_port", al_data->srcport); if (al_data->dstip) cJSON_AddStringToObject(root, "dst_ip", al_data->dstip); if (al_data->dstport) cJSON_AddNumberToObject(root, "dst_port", al_data->dstport); if (al_data->filename) cJSON_AddStringToObject(root, "file", al_data->filename); if (al_data->old_md5) cJSON_AddStringToObject(root, "md5_old", al_data->old_md5); if (al_data->new_md5) cJSON_AddStringToObject(root, "md5_new", al_data->new_md5); if (al_data->old_sha1) cJSON_AddStringToObject(root, "sha1_old", al_data->old_sha1); if (al_data->new_sha1) cJSON_AddStringToObject(root, "sha1_new", al_data->new_sha1); #ifdef GEOIP if (al_data->geoipdatasrc) cJSON_AddStringToObject(root, "src_city", al_data->geoipdatasrc); if (al_data->geoipdatadst) cJSON_AddStringToObject(root, "dst_city", al_data->geoipdatadst); #endif // Create the JSON String json_string = cJSON_PrintUnformatted(root); // Create the syslog message snprintf(syslog_msg, OS_SIZE_2048 - padding, "<%d>%s %s ossec: %s", /* syslog header */ syslog_config->priority, tstamp, __shost, /* JSON Encoded Data */ json_string ); // Cleanup the memory for the JSON Structure free(json_string); cJSON_Delete(root); } else if(syslog_config->format == SPLUNK_CSYSLOG) { /* Build a Splunk Style Key/Value string for logging */ snprintf(syslog_msg, OS_SIZE_2048, "<%d>%s %s ossec: crit=%d id=%d description=\"%s\" component=\"%s\",", /* syslog header */ syslog_config->priority, tstamp, __shost, /* OSSEC metadata */ al_data->level, al_data->rule, al_data->comment, al_data->location ); /* Event specifics */ field_add_string(syslog_msg, OS_SIZE_2048, " classification=\"%s\",", al_data->group ); if( field_add_string(syslog_msg, OS_SIZE_2048, " src_ip=\"%s\",", al_data->srcip ) > 0 ) field_add_int(syslog_msg, OS_SIZE_2048, " src_port=%d,", al_data->srcport ); #ifdef GEOIP field_add_string(syslog_msg, OS_SIZE_2048, " src_city=\"%s\",", al_data->geoipdatasrc ); field_add_string(syslog_msg, OS_SIZE_2048, " dst_city=\"%s\",", al_data->geoipdatadst ); #endif if( field_add_string(syslog_msg, OS_SIZE_2048, " dst_ip=\"%s\",", al_data->dstip ) > 0 ) field_add_int(syslog_msg, OS_SIZE_2048, " dst_port=%d,", al_data->dstport ); field_add_string(syslog_msg, OS_SIZE_2048, " file=\"%s\",", al_data->filename ); field_add_string(syslog_msg, OS_SIZE_2048, " acct=\"%s\",", al_data->user ); field_add_string(syslog_msg, OS_SIZE_2048, " md5_old=\"%s\",", al_data->old_md5 ); field_add_string(syslog_msg, OS_SIZE_2048, " md5_new=\"%s\",", al_data->new_md5 ); field_add_string(syslog_msg, OS_SIZE_2048, " sha1_old=\"%s\",", al_data->old_sha1 ); field_add_string(syslog_msg, OS_SIZE_2048, " sha1_new=\"%s\",", al_data->new_sha1 ); /* Message */ field_add_truncated(syslog_msg, OS_SIZE_2048, " message=\"%s\"", al_data->log[0], 2 ); } OS_SendUDPbySize(syslog_config->socket, strlen(syslog_msg), syslog_msg); return(1); }
/* FW_Log: v0.1, 2005/12/30 */ int FW_Log(Eventinfo *lf) { /* If we don't have the srcip or the * action, there is no point in going * forward over here */ if(!lf->action || !lf->srcip) { return(0); } /* Setting the actions */ switch(*lf->action) { /* discard, drop, deny, */ case 'd': case 'D': /* reject, */ case 'r': case 'R': /* block */ case 'b': case 'B': os_free(lf->action); os_strdup("DROP", lf->action); break; /* Closed */ case 'c': case 'C': /* Teardown */ case 't': case 'T': os_free(lf->action); os_strdup("CLOSED", lf->action); break; /* allow, accept, */ case 'a': case 'A': /* pass/permitted */ case 'p': case 'P': /* open */ case 'o': case 'O': os_free(lf->action); os_strdup("ALLOW", lf->action); break; default: if(OSMatch_Execute(lf->action,strlen(lf->action),&FWDROPpm)) { os_free(lf->action); os_strdup("DROP", lf->action); } if(OSMatch_Execute(lf->action,strlen(lf->action),&FWALLOWpm)) { os_free(lf->action); os_strdup("ALLOW", lf->action); } else { os_free(lf->action); os_strdup("UNKNOWN", lf->action); } break; } /* log to file */ fprintf(_fflog, "%d %s %02d %s %s%s%s %s %s %s:%s->%s:%s\n", lf->year, lf->mon, lf->day, lf->hour, lf->hostname != lf->location?lf->hostname:"", lf->hostname != lf->location?"->":"", lf->location, lf->action, lf->protocol, lf->srcip, lf->srcport, lf->dstip, lf->dstport); fflush(_fflog); return(1); }
/* CheckIfRuleMatch v0.1 * Will check if the currently_rule matches the event information */ RuleInfo *OS_CheckIfRuleMatch(Eventinfo *lf, RuleNode *curr_node) { /* We check for: * decoded_as, * fts, * word match (fast regex), * regex, * url, * id, * user, * maxsize, * protocol, * srcip, * dstip, * srcport, * dstport, * time, * weekday, * status, */ RuleInfo *currently_rule = curr_node->ruleinfo; /* Can't be null */ if(!currently_rule) { merror("%s: Inconsistent state. currently rule NULL", ARGV0); return(NULL); } #ifdef TESTRULE if(full_output && !alert_only) print_out(" Trying rule: %d - %s", currently_rule->sigid, currently_rule->comment); #endif /* Checking if any decoder pre-matched here */ if(currently_rule->decoded_as && currently_rule->decoded_as != lf->decoder_info->id) { return(NULL); } /* Checking program name */ if(currently_rule->program_name) { if(!lf->program_name) return(NULL); if(!OSMatch_Execute(lf->program_name, lf->p_name_size, currently_rule->program_name)) return(NULL); } /* Checking for the id */ if(currently_rule->id) { if(!lf->id) { return(NULL); } if(!OSMatch_Execute(lf->id, strlen(lf->id), currently_rule->id)) return(NULL); #ifdef CDBLOOKUP #endif } /* Checking if any word to match exists */ if(currently_rule->match) { if(!OSMatch_Execute(lf->log, lf->size, currently_rule->match)) return(NULL); } /* Checking if exist any regex for this rule */ if(currently_rule->regex) { if(!OSRegex_Execute(lf->log, currently_rule->regex)) return(NULL); } /* Checking for actions */ if(currently_rule->action) { if(!lf->action) return(NULL); if(strcmp(currently_rule->action,lf->action) != 0) return(NULL); } /* Checking for the url */ if(currently_rule->url) { if(!lf->url) { return(NULL); } if(!OSMatch_Execute(lf->url, strlen(lf->url), currently_rule->url)) { return(NULL); } #ifdef CDBLOOKUP #endif } /* Getting tcp/ip packet information */ if(currently_rule->alert_opts & DO_PACKETINFO) { /* Checking for the srcip */ if(currently_rule->srcip) { if(!lf->srcip) { return(NULL); } if(!OS_IPFoundList(lf->srcip, currently_rule->srcip)) { return(NULL); } #ifdef CDBLOOKUP #endif } /* Checking for the dstip */ if(currently_rule->dstip) { if(!lf->dstip) { return(NULL); } if(!OS_IPFoundList(lf->dstip, currently_rule->dstip)) { return(NULL); } #ifdef CDBLOOKUP #endif } if(currently_rule->srcport) { if(!lf->srcport) { return(NULL); } if(!OSMatch_Execute(lf->srcport, strlen(lf->srcport), currently_rule->srcport)) { return(NULL); } #ifdef CDBLOOKUP #endif } if(currently_rule->dstport) { if(!lf->dstport) { return(NULL); } if(!OSMatch_Execute(lf->dstport, strlen(lf->dstport), currently_rule->dstport)) { return(NULL); } #ifdef CDBLOOKUP #endif } } /* END PACKET_INFO */ /* Extra information from event */ if(currently_rule->alert_opts & DO_EXTRAINFO) { /* Checking compiled rule. */ if(currently_rule->compiled_rule) { if(!currently_rule->compiled_rule(lf)) { return(NULL); } } /* Checking if exist any user to match */ if(currently_rule->user) { if(lf->dstuser) { if(!OSMatch_Execute(lf->dstuser, strlen(lf->dstuser), currently_rule->user)) return(NULL); } else if(lf->srcuser) { if(!OSMatch_Execute(lf->srcuser, strlen(lf->srcuser), currently_rule->user)) return(NULL); } else #ifdef CDBLOOKUP #endif { /* no user set */ return(NULL); } } /* Checking if any rule related to the size exist */ if(currently_rule->maxsize) { if(lf->size < currently_rule->maxsize) return(NULL); } /* Checking if we are in the right time */ if(currently_rule->day_time) { if(!OS_IsonTime(lf->hour, currently_rule->day_time)) { return(NULL); } } /* Checking week day */ if(currently_rule->week_day) { if(!OS_IsonDay(__crt_wday, currently_rule->week_day)) { return(NULL); } } /* Getting extra data */ if(currently_rule->extra_data) { if(!lf->data) return(NULL); if(!OSMatch_Execute(lf->data, strlen(lf->data), currently_rule->extra_data)) return(NULL); } /* Checking hostname */ if(currently_rule->hostname) { if(!lf->hostname) return(NULL); if(!OSMatch_Execute(lf->hostname, strlen(lf->hostname), currently_rule->hostname)) return(NULL); } /* Checking for status */ if(currently_rule->status) { if(!lf->status) return(NULL); if(!OSMatch_Execute(lf->status, strlen(lf->status), currently_rule->status)) return(NULL); } /* Do diff check. */ if(currently_rule->context_opts & SAME_DODIFF) { if(!doDiff(currently_rule, lf)) { return(NULL); } } } /* Checking for the FTS flag */ if(currently_rule->alert_opts & DO_FTS) { /** FTS CHECKS **/ if(lf->decoder_info->fts) { if(lf->decoder_info->fts & FTS_DONE) { /* We already did the fts in here. */ } else if(!FTS(lf)) { return(NULL); } } else { return(NULL); } } /* List lookups */ if(currently_rule->lists != NULL) { ListRule *list_holder=currently_rule->lists; while(list_holder) { switch(list_holder->field) { case RULE_SRCIP: if(!lf->srcip) return(NULL); if(!OS_DBSearch(list_holder,lf->srcip)) return(NULL); break; case RULE_SRCPORT: if(!lf->srcport) return(NULL); if(!OS_DBSearch(list_holder,lf->srcport)) return(NULL); break; case RULE_DSTIP: if(!lf->dstip) return(NULL); if(!OS_DBSearch(list_holder,lf->dstip)) return(NULL); break; case RULE_DSTPORT: if(!lf->dstport) return(NULL); if(!OS_DBSearch(list_holder,lf->dstport)) return(NULL); break; case RULE_USER: if(lf->srcuser) { if(!OS_DBSearch(list_holder,lf->srcuser)) return(NULL); } else if(lf->dstuser) { if(!OS_DBSearch(list_holder,lf->dstuser)) return(NULL); } else { return(NULL); } break; case RULE_URL: if(!lf->url) return(NULL); if(!OS_DBSearch(list_holder,lf->url)) return(NULL); break; case RULE_ID: if(!lf->id) return(NULL); if(!OS_DBSearch(list_holder,lf->id)) return(NULL); break; case RULE_HOSTNAME: if(!lf->hostname) return(NULL); if(!OS_DBSearch(list_holder,lf->hostname)) return(NULL); break; case RULE_PROGRAM_NAME: if(!lf->program_name) return(NULL); if(!OS_DBSearch(list_holder,lf->program_name)) return(NULL); break; case RULE_STATUS: if(!lf->status) return(NULL); if(!OS_DBSearch(list_holder,lf->status)) return(NULL); break; case RULE_ACTION: if(!lf->action) return(NULL); if(!OS_DBSearch(list_holder,lf->action)) return(NULL); break; default: return(NULL); } list_holder = list_holder->next; } } /* If it is a context rule, search for it */ if(currently_rule->context == 1) { if(!currently_rule->event_search(lf, currently_rule)) return(NULL); } #ifdef TESTRULE if(full_output && !alert_only) print_out(" *Rule %d matched.", currently_rule->sigid); #endif /* Search for dependent rules */ if(curr_node->child) { RuleNode *child_node = curr_node->child; RuleInfo *child_rule = NULL; #ifdef TESTRULE if(full_output && !alert_only) print_out(" *Trying child rules."); #endif while(child_node) { child_rule = OS_CheckIfRuleMatch(lf, child_node); if(child_rule != NULL) { return(child_rule); } child_node = child_node->next; } } /* If we are set to no alert, keep going */ if(currently_rule->alert_opts & NO_ALERT) { return(NULL); } hourly_alerts++; currently_rule->firedtimes++; return(currently_rule); /* Matched */ }
/** int OS_Alert_SendSyslog * Sends an alert via syslog. * Returns 1 on success or 0 on error. */ int OS_Alert_SendSyslog(alert_data *al_data, SyslogConfig *syslog_config) { char *tstamp; char user_msg[256]; char srcip_msg[256]; char syslog_msg[OS_SIZE_2048 +1]; /* Invalid socket. */ if(syslog_config->socket < 0) { return(0); } /* Clearing the memory before insert */ memset(syslog_msg, '\0', OS_SIZE_2048 +1); /* Looking if location is set */ if(syslog_config->location) { if(!OSMatch_Execute(al_data->location, strlen(al_data->location), syslog_config->location)) { return(0); } } /* Looking for the level */ if(syslog_config->level) { if(al_data->level < syslog_config->level) { return(0); } } /* Looking for rule id */ if(syslog_config->rule_id) { int id_i = 0; while(syslog_config->rule_id[id_i] != 0) { if(syslog_config->rule_id[id_i] == al_data->rule) { break; } id_i++; } /* If we found, id is going to be a valid rule */ if(!syslog_config->rule_id[id_i]) { return(0); } } /* Looking for the group */ if(syslog_config->group) { if(!OSMatch_Execute(al_data->group, strlen(al_data->group), syslog_config->group)) { return(0); } } /* Fixing the timestamp to be syslog compatible. * We have 2008 Jul 10 10:11:23 * Should be: Jul 10 10:11:23 */ tstamp = al_data->date; if(strlen(al_data->date) > 14) { tstamp+=5; /* Fixing first digit if the day is < 10 */ if(tstamp[4] == '0') tstamp[4] = ' '; } /* Adding source ip. */ if(!al_data->srcip || ((al_data->srcip[0] == '(') && (al_data->srcip[1] == 'n') && (al_data->srcip[2] == 'o'))) { srcip_msg[0] = '\0'; } else { snprintf(srcip_msg, 255, " srcip: %s;", al_data->srcip); } /* Adding username. */ if(!al_data->user || ((al_data->user[0] == '(') && (al_data->user[1] == 'n') && (al_data->user[2] == 'o'))) { user_msg[0] = '\0'; } else { snprintf(user_msg, 255, " user: %s;", al_data->user); } /* Inserting data */ if(syslog_config->format == DEFAULT_CSYSLOG) { /* Building syslog message. */ snprintf(syslog_msg, OS_SIZE_2048, "<%d>%s %s ossec: Alert Level: %d; Rule: %d - %s; " "Location: %s;%s%s %s", syslog_config->priority, tstamp, __shost, al_data->level, al_data->rule, al_data->comment, al_data->location, /* Source ip. */ srcip_msg, user_msg, al_data->log[0]); } OS_SendUDPbySize(syslog_config->socket, strlen(syslog_msg), syslog_msg); return(1); }
/* Use the osdecoders to decode the received event */ void DecodeEvent(Eventinfo *lf) { OSDecoderNode *node; OSDecoderNode *child_node; OSDecoderInfo *nnode; const char *llog = NULL; const char *pmatch = NULL; const char *cmatch = NULL; const char *regex_prev = NULL; node = OS_GetFirstOSDecoder(lf->program_name); if (!node) { return; } #ifdef TESTRULE if (!alert_only) { print_out("\n**Phase 2: Completed decoding."); } #endif do { nnode = node->osdecoder; /* First check program name */ if (lf->program_name) { if (!OSMatch_Execute(lf->program_name, lf->p_name_size, nnode->program_name)) { continue; } pmatch = lf->log; } /* If prematch fails, go to the next osdecoder in the list */ if (nnode->prematch) { if (!(pmatch = OSRegex_Execute(lf->log, nnode->prematch))) { continue; } /* Next character */ if (*pmatch != '\0') { pmatch++; } } #ifdef TESTRULE if (!alert_only) { print_out(" decoder: '%s'", nnode->name); } #endif lf->decoder_info = nnode; child_node = node->child; /* If no child node is set, set the child node * as if it were the child (ugh) */ if (!child_node) { child_node = node; } else { /* Check if we have any child osdecoder */ while (child_node) { nnode = child_node->osdecoder; /* If we have a pre match and it matches, keep * going. If we don't have a prematch, stop * and go for the regexes. */ if (nnode->prematch) { const char *llog2; /* If we have an offset set, use it */ if (nnode->prematch_offset & AFTER_PARENT) { llog2 = pmatch; } else { llog2 = lf->log; } if ((cmatch = OSRegex_Execute(llog2, nnode->prematch))) { if (*cmatch != '\0') { cmatch++; } lf->decoder_info = nnode; break; } } else { cmatch = pmatch; break; } /* If we have multiple regex-only childs, * do not attempt to go any further with them. */ if (child_node->osdecoder->get_next) { do { child_node = child_node->next; } while (child_node && child_node->osdecoder->get_next); if (!child_node) { return; } child_node = child_node->next; nnode = NULL; } else { child_node = child_node->next; nnode = NULL; } } } /* Nothing matched */ if (!nnode) { return; } /* If we have an external decoder, execute it */ if (nnode->plugindecoder) { nnode->plugindecoder(lf); return; } /* Get the regex */ while (child_node) { if (nnode->regex) { int i; /* With regex we have multiple options * regarding the offset: * after the prematch, * after the parent, * after some previous regex, * or any offset */ if (nnode->regex_offset) { if (nnode->regex_offset & AFTER_PARENT) { llog = pmatch; } else if (nnode->regex_offset & AFTER_PREMATCH) { llog = cmatch; } else if (nnode->regex_offset & AFTER_PREVREGEX) { if (!regex_prev) { llog = cmatch; } else { llog = regex_prev; } } } else { llog = lf->log; } /* If Regex does not match, return */ if (!(regex_prev = OSRegex_Execute(llog, nnode->regex))) { if (nnode->get_next) { child_node = child_node->next; nnode = child_node->osdecoder; continue; } return; } /* Fix next pointer */ if (*regex_prev != '\0') { regex_prev++; } for (i = 0; nnode->regex->sub_strings[i]; i++) { if (lf->nfields >= Config.decoder_order_size) { merror("%s: ERROR: Regex has too many groups.", ARGV0); return; } if (nnode->order[i]) nnode->order[i](lf, nnode->regex->sub_strings[i], nnode->fields[i]); else /* We do not free any memory used above */ os_free(nnode->regex->sub_strings[i]); nnode->regex->sub_strings[i] = NULL; } /* If we have a next regex, try getting it */ if (nnode->get_next) { child_node = child_node->next; nnode = child_node->osdecoder; continue; } break; } /* If we don't have a regex, we may leave now */ return; } /* ok to return */ return; } while ((node = node->next) != NULL); #ifdef TESTRULE if (!alert_only) { print_out(" No decoder matched."); } #endif }
/** int OS_Alert_SendSyslog * Sends an alert via syslog. * Returns 1 on success or 0 on error. */ int OS_Alert_SendSyslog(alert_data *al_data, SyslogConfig *syslog_config) { char *tstamp; char syslog_msg[OS_SIZE_2048]; /* These will be Malloc'd, so no need to predeclare size, just remember to free! */ char *json_safe_comment; char *json_safe_message; /* padding value */ int padding = 0; /* Invalid socket. */ if(syslog_config->socket < 0) { return(0); } /* Clearing the memory before insert */ memset(syslog_msg, '\0', OS_SIZE_2048); /* Looking if location is set */ if(syslog_config->location) { if(!OSMatch_Execute(al_data->location, strlen(al_data->location), syslog_config->location)) { return(0); } } /* Looking for the level */ if(syslog_config->level) { if(al_data->level < syslog_config->level) { return(0); } } /* Looking for rule id */ if(syslog_config->rule_id) { int id_i = 0; while(syslog_config->rule_id[id_i] != 0) { if(syslog_config->rule_id[id_i] == al_data->rule) { break; } id_i++; } /* If we found, id is going to be a valid rule */ if(!syslog_config->rule_id[id_i]) { return(0); } } /* Looking for the group */ if(syslog_config->group) { if(!OSMatch_Execute(al_data->group, strlen(al_data->group), syslog_config->group)) { return(0); } } /* Fixing the timestamp to be syslog compatible. * We have 2008 Jul 10 10:11:23 * Should be: Jul 10 10:11:23 */ tstamp = al_data->date; if(strlen(al_data->date) > 14) { tstamp+=5; /* Fixing first digit if the day is < 10 */ if(tstamp[4] == '0') tstamp[4] = ' '; } /* Remove the double quotes from "dangerous" fields */ if( (json_safe_comment = os_strip_char(al_data->comment, '"')) == NULL ) { return(0); } if( (json_safe_message = os_strip_char(al_data->log[0], '"')) == NULL ) { return(0); } /* Inserting data */ if(syslog_config->format == DEFAULT_CSYSLOG) { /* Building syslog message. */ snprintf(syslog_msg, OS_SIZE_2048, "<%d>%s %s ossec: Alert Level: %d; Rule: %d - %s; Location: %s;", syslog_config->priority, tstamp, __shost, al_data->level, al_data->rule, al_data->comment, al_data->location ); field_add_string(syslog_msg, OS_SIZE_2048, " srcip: %s;", al_data->srcip ); #ifdef GEOIP field_add_string(syslog_msg, OS_SIZE_2048, " srccity: %s;", al_data->geoipdatasrc ); field_add_string(syslog_msg, OS_SIZE_2048, " dstcity: %s;", al_data->geoipdatadst ); #endif field_add_string(syslog_msg, OS_SIZE_2048, " dstip: %s;", al_data->dstip ); field_add_string(syslog_msg, OS_SIZE_2048, " user: %s;", al_data->user ); field_add_string(syslog_msg, OS_SIZE_2048, " Previous MD5: %s;", al_data->old_md5 ); field_add_string(syslog_msg, OS_SIZE_2048, " Current MD5: %s;", al_data->new_md5 ); field_add_string(syslog_msg, OS_SIZE_2048, " Previous SHA1: %s;", al_data->old_sha1 ); field_add_string(syslog_msg, OS_SIZE_2048, " Current SHA1: %s;", al_data->new_sha1 ); field_add_truncated(syslog_msg, OS_SIZE_2048, " %s", al_data->log[0], 2 ); } else if(syslog_config->format == CEF_CSYSLOG) { snprintf(syslog_msg, OS_SIZE_2048, "<%d>%s CEF:0|%s|%s|%s|%d|%s|%d|dvc=%s cs2=%s cs2Label=Location", syslog_config->priority, tstamp, __author, __ossec_name, __version, al_data->rule, al_data->comment, (al_data->level > 10) ? 10 : al_data->level, __shost, al_data->location); field_add_string(syslog_msg, OS_SIZE_2048, " src=%s", al_data->srcip ); #ifdef GEOIP field_add_string(syslog_msg, OS_SIZE_2048, " cs3Label=SrcCity cs3=%s", al_data->geoipdatasrc ); field_add_string(syslog_msg, OS_SIZE_2048, " cs4Label=DstCity cs4=%s", al_data->geoipdatadst ); #endif field_add_string(syslog_msg, OS_SIZE_2048, " suser=%s", al_data->user ); field_add_string(syslog_msg, OS_SIZE_2048, " dst=%s", al_data->dstip ); field_add_truncated(syslog_msg, OS_SIZE_2048, " msg=%s", al_data->log[0], 2 ); if (al_data->new_md5 && al_data->new_sha1) { field_add_string(syslog_msg, OS_SIZE_2048, " Previous MD5: %s", al_data->old_md5 ); field_add_string(syslog_msg, OS_SIZE_2048, " Current MD5: %s", al_data->new_md5 ); field_add_string(syslog_msg, OS_SIZE_2048, " Previous SHA1: %s", al_data->old_sha1 ); field_add_string(syslog_msg, OS_SIZE_2048, " Current SHA1: %s", al_data->new_sha1 ); } } else if(syslog_config->format == JSON_CSYSLOG) { // Padding is two to make sure we can fit closign bracket padding = 2; /* Build a JSON Object for logging */ snprintf(syslog_msg, OS_SIZE_2048 - padding, "<%d>%s %s ossec: { \"crit\": %d, \"id\": %d, \"description\": \"%s\", \"component\": \"%s\",", /* syslog header */ syslog_config->priority, tstamp, __shost, /* OSSEC metadata */ al_data->level, al_data->rule, json_safe_comment, al_data->location ); /* Event specifics */ field_add_string(syslog_msg, OS_SIZE_2048 - padding, " \"classification\": \"%s\",", al_data->group ); if( field_add_string(syslog_msg, OS_SIZE_2048 - padding, " \"src_ip\": \"%s\",", al_data->srcip ) > 0 ) field_add_int(syslog_msg, OS_SIZE_2048 - padding, " \"src_port\": %d,", al_data->srcport ); #ifdef GEOIP field_add_string(syslog_msg, OS_SIZE_2048 - padding, " \"src_city\": \"%s\",", al_data->geoipdatasrc ); field_add_string(syslog_msg, OS_SIZE_2048 - padding, " \"dst_city\": \"%s\",", al_data->geoipdatadst ); #endif if ( field_add_string(syslog_msg, OS_SIZE_2048 - padding, " \"dst_ip\": \"%s\",", al_data->dstip ) > 0 ) field_add_int(syslog_msg, OS_SIZE_2048 - padding, " \"dst_port\": %d,", al_data->dstport ); field_add_string(syslog_msg, OS_SIZE_2048 - padding, " \"file\": \"%s\",", al_data->filename ); field_add_string(syslog_msg, OS_SIZE_2048 - padding, " \"acct\": \"%s\",", al_data->user ); field_add_string(syslog_msg, OS_SIZE_2048 - padding, " \"md5_old\": \"%s\",", al_data->old_md5 ); field_add_string(syslog_msg, OS_SIZE_2048 - padding, " \"md5_new\": \"%s\",", al_data->new_md5 ); field_add_string(syslog_msg, OS_SIZE_2048 - padding, " \"sha1_old\": \"%s\",", al_data->old_sha1 ); field_add_string(syslog_msg, OS_SIZE_2048 - padding, " \"sha1_new\": \"%s\",", al_data->new_sha1 ); /* Message */ field_add_truncated(syslog_msg, OS_SIZE_2048 - padding, " \"message\": \"%s\"", json_safe_message, 2 ); /* Closing brace */ field_add_string(syslog_msg, OS_SIZE_2048, " }", "" ); } else if(syslog_config->format == SPLUNK_CSYSLOG) { /* Build a Splunk Style Key/Value string for logging */ snprintf(syslog_msg, OS_SIZE_2048, "<%d>%s %s ossec: crit=%d id=%d description=\"%s\" component=\"%s\",", /* syslog header */ syslog_config->priority, tstamp, __shost, /* OSSEC metadata */ al_data->level, al_data->rule, json_safe_comment, al_data->location ); /* Event specifics */ field_add_string(syslog_msg, OS_SIZE_2048, " classification=\"%s\",", al_data->group ); if( field_add_string(syslog_msg, OS_SIZE_2048, " src_ip=\"%s\",", al_data->srcip ) > 0 ) field_add_int(syslog_msg, OS_SIZE_2048, " src_port=%d,", al_data->srcport ); #ifdef GEOIP field_add_string(syslog_msg, OS_SIZE_2048, " src_city=\"%s\",", al_data->geoipdatasrc ); field_add_string(syslog_msg, OS_SIZE_2048, " dst_city=\"%s\",", al_data->geoipdatadst ); #endif if( field_add_string(syslog_msg, OS_SIZE_2048, " dst_ip=\"%s\",", al_data->dstip ) > 0 ) field_add_int(syslog_msg, OS_SIZE_2048, " dst_port=%d,", al_data->dstport ); field_add_string(syslog_msg, OS_SIZE_2048, " file=\"%s\",", al_data->filename ); field_add_string(syslog_msg, OS_SIZE_2048, " acct=\"%s\",", al_data->user ); field_add_string(syslog_msg, OS_SIZE_2048, " md5_old=\"%s\",", al_data->old_md5 ); field_add_string(syslog_msg, OS_SIZE_2048, " md5_new=\"%s\",", al_data->new_md5 ); field_add_string(syslog_msg, OS_SIZE_2048, " sha1_old=\"%s\",", al_data->old_sha1 ); field_add_string(syslog_msg, OS_SIZE_2048, " sha1_new=\"%s\",", al_data->new_sha1 ); /* Message */ field_add_truncated(syslog_msg, OS_SIZE_2048, " message=\"%s\"", json_safe_message, 2 ); } OS_SendUDPbySize(syslog_config->socket, strlen(syslog_msg), syslog_msg); /* Free the malloc'd variables */ free(json_safe_comment); free(json_safe_message); return(1); }
/** main **/ int main(int argc, char **argv) { char *pattern; char msg[OS_MAXSTR +1]; memset(msg, '\0', OS_MAXSTR +1); OSRegex regex; OSMatch matcher; OS_SetName(ARGV0); /* user arguments */ if(argc != 2) { helpmsg(); return(-1); } /* User options */ if(strcmp(argv[1], "-h") == 0) { helpmsg(); return(-1); } os_strdup(argv[1], pattern); if(!OSRegex_Compile(pattern, ®ex, 0)) { printf("pattern does not compile with OSRegex_Compile\n"); return(-1); } if(!OSMatch_Compile(pattern, &matcher, 0)) { printf("pattern does not compile with OSMatch_Compile\n"); return(-1); } while((fgets(msg, OS_MAXSTR, stdin)) != NULL) { /* Removing new line. */ if(msg[strlen(msg) -1] == '\n') msg[strlen(msg) -1] = '\0'; /* Make sure we ignore blank lines. */ if(strlen(msg) < 2) { continue; } if(OSRegex_Execute(msg, ®ex)) printf("+OSRegex_Execute: %s\n",msg); /* else printf("-OSRegex_Execute: \n"); */ if(OS_Regex(pattern, msg)) printf("+OS_Regex : %s\n", msg); /* else printf("-OS_Regex: \n"); */ if(OSMatch_Execute(msg, strlen(msg), &matcher)) printf("+OSMatch_Compile: %s\n", msg); if(OS_Match2(pattern, msg)) printf("+OS_Match2 : %s\n", msg); } return(0); }
/* Send an alert via syslog * Returns 1 on success or 0 on error */ int OS_Alert_SendSyslog(alert_data *al_data, const SyslogConfig *syslog_config) { char *tstamp; char *hostname; char syslog_msg[OS_SIZE_2048]; /* Invalid socket */ if (syslog_config->socket < 0) { return (0); } /* Clear the memory before insert */ memset(syslog_msg, '\0', OS_SIZE_2048); /* Look if location is set */ if (syslog_config->location) { if (!OSMatch_Execute(al_data->location, strlen(al_data->location), syslog_config->location)) { return (0); } } /* Look for the level */ if (syslog_config->level) { if (al_data->level < syslog_config->level) { return (0); } } /* Look for rule id */ if (syslog_config->rule_id) { int id_i = 0; while (syslog_config->rule_id[id_i] != 0) { if (syslog_config->rule_id[id_i] == al_data->rule) { break; } id_i++; } /* If we found, id is going to be a valid rule */ if (!syslog_config->rule_id[id_i]) { return (0); } } /* Look for the group */ if (syslog_config->group) { if (!OSMatch_Execute(al_data->group, strlen(al_data->group), syslog_config->group)) { return (0); } } /* Fix the timestamp to be syslog compatible * We have 2008 Jul 10 10:11:23 * Should be: Jul 10 10:11:23 */ tstamp = al_data->date; if (strlen(al_data->date) > 14) { tstamp += 5; /* Fix first digit if the day is < 10 */ if (tstamp[4] == '0') { tstamp[4] = ' '; } } if (syslog_config->use_fqdn) { hostname = __shost_long; } else { hostname = __shost; } /* Insert data */ if (syslog_config->format == DEFAULT_CSYSLOG) { /* Build syslog message */ snprintf(syslog_msg, OS_SIZE_2048, "<%u>%s %s ossec: Alert Level: %u; Rule: %u - %s; Location: %s;", syslog_config->priority, tstamp, hostname, al_data->level, al_data->rule, al_data->comment, al_data->location ); field_add_string(syslog_msg, OS_SIZE_2048, " classification: %s;", al_data->group ); field_add_string(syslog_msg, OS_SIZE_2048, " srcip: %s;", al_data->srcip ); #ifdef LIBGEOIP_ENABLED field_add_string(syslog_msg, OS_SIZE_2048, " srccity: %s;", al_data->srcgeoip ); field_add_string(syslog_msg, OS_SIZE_2048, " dstcity: %s;", al_data->dstgeoip ); #endif field_add_string(syslog_msg, OS_SIZE_2048, " dstip: %s;", al_data->dstip ); field_add_string(syslog_msg, OS_SIZE_2048, " user: %s;", al_data->user ); field_add_string(syslog_msg, OS_SIZE_2048, " Previous MD5: %s;", al_data->old_md5 ); field_add_string(syslog_msg, OS_SIZE_2048, " Current MD5: %s;", al_data->new_md5 ); field_add_string(syslog_msg, OS_SIZE_2048, " Previous SHA1: %s;", al_data->old_sha1 ); field_add_string(syslog_msg, OS_SIZE_2048, " Current SHA1: %s;", al_data->new_sha1 ); /* "9/19/2016 - Sivakumar Nellurandi - parsing additions" */ field_add_string(syslog_msg, OS_SIZE_2048, " Size changed: from %s;", al_data->file_size ); field_add_string(syslog_msg, OS_SIZE_2048, " User ownership: was %s;", al_data->owner_chg ); field_add_string(syslog_msg, OS_SIZE_2048, " Group ownership: was %s;", al_data->group_chg ); field_add_string(syslog_msg, OS_SIZE_2048, " Permissions changed: from %s;", al_data->perm_chg ); /* "9/19/2016 - Sivakumar Nellurandi - parsing additions" */ field_add_truncated(syslog_msg, OS_SIZE_2048, " %s", al_data->log[0], 2 ); } else if (syslog_config->format == CEF_CSYSLOG) { snprintf(syslog_msg, OS_SIZE_2048, "<%u>%s CEF:0|%s|%s|%s|%u|%s|%u|dvc=%s cs1=%s cs1Label=Location", syslog_config->priority, tstamp, __author, __ossec_name, __version, al_data->rule, al_data->comment, (al_data->level > 10) ? 10 : al_data->level, hostname, al_data->location); field_add_string(syslog_msg, OS_SIZE_2048, " classification=%s", al_data->group ); field_add_string(syslog_msg, OS_SIZE_2048, " src=%s", al_data->srcip ); field_add_int(syslog_msg, OS_SIZE_2048, " dpt=%d", al_data->dstport ); field_add_int(syslog_msg, OS_SIZE_2048, " spt=%d", al_data->srcport ); field_add_string(syslog_msg, OS_SIZE_2048, " fname=%s", al_data->filename ); field_add_string(syslog_msg, OS_SIZE_2048, " dhost=%s", al_data->dstip ); field_add_string(syslog_msg, OS_SIZE_2048, " shost=%s", al_data->srcip ); field_add_string(syslog_msg, OS_SIZE_2048, " suser=%s", al_data->user ); field_add_string(syslog_msg, OS_SIZE_2048, " dst=%s", al_data->dstip ); #ifdef LIBGEOIP_ENABLED field_add_string(syslog_msg, OS_SIZE_2048, " cs4Label=SrcCity cs4=%s", al_data->srcgeoip ); field_add_string(syslog_msg, OS_SIZE_2048, " cs5Label=DstCity cs5=%s", al_data->dstgeoip ); #endif field_add_string(syslog_msg, OS_SIZE_2048, " suser=%s", al_data->user ); field_add_string(syslog_msg, OS_SIZE_2048, " dst=%s", al_data->dstip ); field_add_truncated(syslog_msg, OS_SIZE_2048, " msg=%s", al_data->log[0], 2 ); if (al_data->new_md5 && al_data->new_sha1) { field_add_string(syslog_msg, OS_SIZE_2048, " cs2Label=OldMD5 cs2=%s", al_data->old_md5); field_add_string(syslog_msg, OS_SIZE_2048, " cs3Label=NewMD5 cs3=%s", al_data->new_md5); field_add_string(syslog_msg, OS_SIZE_2048, " oldFileHash=%s", al_data->old_sha1 ); field_add_string(syslog_msg, OS_SIZE_2048, " fhash=%s", al_data->new_sha1 ); field_add_string(syslog_msg, OS_SIZE_2048, " fileHash=%s", al_data->new_sha1 ); } } else if (syslog_config->format == JSON_CSYSLOG) { /* Build a JSON Object for logging */ cJSON *root; char *json_string; root = cJSON_CreateObject(); /* Data guaranteed to be there */ cJSON_AddNumberToObject(root, "crit", al_data->level); cJSON_AddNumberToObject(root, "id", al_data->rule); cJSON_AddStringToObject(root, "component", al_data->location); /* Rule Meta Data */ if (al_data->group) { cJSON_AddStringToObject(root, "classification", al_data->group); } if (al_data->comment) { cJSON_AddStringToObject(root, "description", al_data->comment); } /* Raw log message generating event */ if (al_data->log && al_data->log[0]) { cJSON_AddStringToObject(root, "message", al_data->log[0]); } /* Add data if it exists */ if (al_data->user) { cJSON_AddStringToObject(root, "acct", al_data->user); } if (al_data->srcip) { cJSON_AddStringToObject(root, "src_ip", al_data->srcip); } if (al_data->srcport) { cJSON_AddNumberToObject(root, "src_port", al_data->srcport); } if (al_data->dstip) { cJSON_AddStringToObject(root, "dst_ip", al_data->dstip); } if (al_data->dstport) { cJSON_AddNumberToObject(root, "dst_port", al_data->dstport); } if (al_data->filename) { cJSON_AddStringToObject(root, "file", al_data->filename); } if (al_data->old_md5) { cJSON_AddStringToObject(root, "md5_old", al_data->old_md5); } if (al_data->new_md5) { cJSON_AddStringToObject(root, "md5_new", al_data->new_md5); } if (al_data->old_sha1) { cJSON_AddStringToObject(root, "sha1_old", al_data->old_sha1); } if (al_data->new_sha1) { cJSON_AddStringToObject(root, "sha1_new", al_data->new_sha1); } #ifdef LIBGEOIP_ENABLED if (al_data->srcgeoip) { cJSON_AddStringToObject(root, "src_city", al_data->srcgeoip); } if (al_data->dstgeoip) { cJSON_AddStringToObject(root, "dst_city", al_data->dstgeoip); } #endif /* Create the JSON string */ json_string = cJSON_PrintUnformatted(root); /* Create the syslog message */ snprintf(syslog_msg, OS_SIZE_2048, "<%u>%s %s ossec: %s", /* syslog header */ syslog_config->priority, tstamp, hostname, /* JSON Encoded Data */ json_string ); /* Clean up the memory for the JSON structure */ free(json_string); cJSON_Delete(root); } else if (syslog_config->format == SPLUNK_CSYSLOG) { /* Build a Splunk Style Key/Value string for logging */ snprintf(syslog_msg, OS_SIZE_2048, "<%u>%s %s ossec: crit=%u id=%u description=\"%s\" component=\"%s\",", /* syslog header */ syslog_config->priority, tstamp, hostname, /* OSSEC metadata */ al_data->level, al_data->rule, al_data->comment, al_data->location ); /* Event specifics */ field_add_string(syslog_msg, OS_SIZE_2048, " classification=\"%s\",", al_data->group ); if ( field_add_string(syslog_msg, OS_SIZE_2048, " src_ip=\"%s\",", al_data->srcip ) > 0 ) { field_add_int(syslog_msg, OS_SIZE_2048, " src_port=%d,", al_data->srcport ); } #ifdef LIBGEOIP_ENABLED field_add_string(syslog_msg, OS_SIZE_2048, " src_city=\"%s\",", al_data->srcgeoip ); field_add_string(syslog_msg, OS_SIZE_2048, " dst_city=\"%s\",", al_data->dstgeoip ); #endif if ( field_add_string(syslog_msg, OS_SIZE_2048, " dst_ip=\"%s\",", al_data->dstip ) > 0 ) { field_add_int(syslog_msg, OS_SIZE_2048, " dst_port=%d,", al_data->dstport ); } field_add_string(syslog_msg, OS_SIZE_2048, " file=\"%s\",", al_data->filename ); field_add_string(syslog_msg, OS_SIZE_2048, " acct=\"%s\",", al_data->user ); field_add_string(syslog_msg, OS_SIZE_2048, " md5_old=\"%s\",", al_data->old_md5 ); field_add_string(syslog_msg, OS_SIZE_2048, " md5_new=\"%s\",", al_data->new_md5 ); field_add_string(syslog_msg, OS_SIZE_2048, " sha1_old=\"%s\",", al_data->old_sha1 ); field_add_string(syslog_msg, OS_SIZE_2048, " sha1_new=\"%s\",", al_data->new_sha1 ); /* Message */ field_add_truncated(syslog_msg, OS_SIZE_2048, " message=\"%s\"", al_data->log[0], 2 ); } OS_SendUDPbySize(syslog_config->socket, strlen(syslog_msg), syslog_msg); return (1); }
void OS_Exec(int execq, int arq, const Eventinfo *lf, const active_response *ar) { char exec_msg[OS_SIZE_1024 + 1]; const char *ip; const char *user; char *filename = NULL; ip = user = "******"; /* Clean the IP */ if (lf->srcip && (ar->ar_cmd->expect & SRCIP)) { if (strncmp(lf->srcip, "::ffff:", 7) == 0) { ip = lf->srcip + 7; } else { ip = lf->srcip; } /* Check if IP is to be ignored */ if (Config.white_list) { if (OS_IPFoundList(ip, Config.white_list)) { return; } } /* Check if it is a hostname */ if (Config.hostname_white_list) { size_t srcip_size; OSMatch **wl; srcip_size = strlen(ip); wl = Config.hostname_white_list; while (*wl) { if (OSMatch_Execute(ip, srcip_size, *wl)) { return; } wl++; } } } /* Get username */ if (lf->dstuser && (ar->ar_cmd->expect & USERNAME)) { user = lf->dstuser; } /* Get filename */ if (lf->filename && (ar->ar_cmd->expect & FILENAME)) { filename = os_shell_escape(lf->filename); } /* Active Response on the server * The response must be here if the ar->location is set to AS * or the ar->location is set to local (REMOTE_AGENT) and the * event location is from here. */ if ((ar->location & AS_ONLY) || ((ar->location & REMOTE_AGENT) && (lf->location[0] != '(')) ) { if (!(Config.ar & LOCAL_AR)) { goto cleanup; } snprintf(exec_msg, OS_SIZE_1024, "%s %s %s %ld.%ld %d %s %s", ar->name, user, ip, (long int)lf->time, __crt_ftell, lf->generated_rule->sigid, lf->location, filename ? filename : "-"); if (OS_SendUnix(execq, exec_msg, 0) < 0) { merror("%s: Error communicating with execd.", ARGV0); } } /* Active Response to the forwarder */ else if ((Config.ar & REMOTE_AR)) { int rc; /* If lf->location start with a ( was generated by remote agent and its * ID is included in lf->location if missing then it must have been * generated by the local analysisd, so prepend a false id tag */ if (lf->location[0] == '(') { snprintf(exec_msg, OS_SIZE_1024, "%s %c%c%c %s %s %s %s %ld.%ld %d %s %s", lf->location, (ar->location & ALL_AGENTS) ? ALL_AGENTS_C : NONE_C, (ar->location & REMOTE_AGENT) ? REMOTE_AGENT_C : NONE_C, (ar->location & SPECIFIC_AGENT) ? SPECIFIC_AGENT_C : NONE_C, ar->agent_id != NULL ? ar->agent_id : "(null)", ar->name, user, ip, (long int)lf->time, __crt_ftell, lf->generated_rule->sigid, lf->location, filename); } else { snprintf(exec_msg, OS_SIZE_1024, "(local_source) %s %c%c%c %s %s %s %s %ld.%ld %d %s %s", lf->location, (ar->location & ALL_AGENTS) ? ALL_AGENTS_C : NONE_C, (ar->location & REMOTE_AGENT) ? REMOTE_AGENT_C : NONE_C, (ar->location & SPECIFIC_AGENT) ? SPECIFIC_AGENT_C : NONE_C, ar->agent_id != NULL ? ar->agent_id : "(null)", ar->name, user, ip, (long int)lf->time, __crt_ftell, lf->generated_rule->sigid, lf->location, filename); } if ((rc = OS_SendUnix(arq, exec_msg, 0)) < 0) { if (rc == OS_SOCKBUSY) { merror("%s: AR socket busy.", ARGV0); } else { merror("%s: AR socket error (shutdown?).", ARGV0); } merror("%s: Error communicating with ar queue (%d).", ARGV0, rc); } } cleanup: /* Clean up Memory */ free(filename); return; }