diff --git a/src/main.c b/src/main.c index 6019a3c..f639913 100644 --- a/src/main.c +++ b/src/main.c @@ -384,7 +384,7 @@ int search_in_string(char* raw_string, char* search_string) { // https://stackoverflow.com/questions/5901181/c-string-append void annotate_entry(int index, char* annotation_string) { if (index >= 0 && index < total_entries) { - if (all_entries[index].annotation== NULL){ + if (all_entries[index].annotation[0] == '\0'){ strncpy(all_entries[index].annotation, annotation_string, sizeof(all_entries[index].annotation) - 1); all_entries[index].annotation[sizeof(all_entries[index].annotation) - 1] = '\0'; all_entries[index].annotated_flag = 1; @@ -392,8 +392,9 @@ void annotate_entry(int index, char* annotation_string) { char * new_str ; if((new_str = malloc(strlen(all_entries[index].annotation)+strlen(",")+strlen(annotation_string)+1)) != NULL){ new_str[0] = '\0'; // ensures the memory is an empty string - strcat(new_str,","); - strcat(new_str,annotation_string); + strcat(new_str, all_entries[index].annotation); + strcat(new_str, ","); + strcat(new_str, annotation_string); strncpy(all_entries[index].annotation, new_str, sizeof(all_entries[index].annotation) - 1); all_entries[index].annotation[sizeof(all_entries[index].annotation) - 1] = '\0'; free(new_str); @@ -415,224 +416,183 @@ void annotate_suspicious_entries(struct log_entry* dataset) { all_entries[i].annotation[0] = '\0'; } - int is_suspicious = 0; // Flag um zu verfolgen ob bereits annotiert - - // 1. PAYLOAD-GRÖßE: Sehr lange Requests (bereits vorhanden, aber verbessert) + // 1. PAYLOAD-GRÖßE: Sehr lange Requests int url_length = strlen(all_entries[i].url_path); if (url_length > SUSPICIOUS_REQUEST_LEN_THRESHOLD) { annotate_entry(i, "Long Payload"); suspicious_patterns_count++; - is_suspicious = 1; } // 2. PFAD-BASIERTE ANGRIFFE: Häufige Angriffsziele und sensible Pfade - if (!is_suspicious) { - // Git-Repository Zugriffe (häufig bei Recon) - if (search_in_string(all_entries[i].url_path, ".git/") || - search_in_string(all_entries[i].url_path, "/.git")) { - annotate_entry(i, "Git Access"); - suspicious_patterns_count++; - is_suspicious = 1; - } - // Environment-Dateien (kritische Konfigurationsdateien) - else if (search_in_string(all_entries[i].url_path, ".env") || - search_in_string(all_entries[i].url_path, ".config") || - search_in_string(all_entries[i].url_path, "config.php")) { - annotate_entry(i, "Config Access"); - suspicious_patterns_count++; - is_suspicious = 1; - } - // WordPress Admin-Bereiche (häufig attackiert) - else if (search_in_string(all_entries[i].url_path, "wp-admin") || - search_in_string(all_entries[i].url_path, "wp-login") || - search_in_string(all_entries[i].url_path, "wp-config")) { - annotate_entry(i, "WP Attack"); - suspicious_patterns_count++; - is_suspicious = 1; - } - // Database Management Tools - else if (search_in_string(all_entries[i].url_path, "phpmyadmin") || - search_in_string(all_entries[i].url_path, "phpMyAdmin") || - search_in_string(all_entries[i].url_path, "adminer")) { - annotate_entry(i, "DB Tool Access"); - suspicious_patterns_count++; - is_suspicious = 1; - } - // Admin/Management Interfaces - else if (search_in_string(all_entries[i].url_path, "/admin") || - search_in_string(all_entries[i].url_path, "/manager") || - search_in_string(all_entries[i].url_path, "/console")) { - annotate_entry(i, "Admin Access"); - suspicious_patterns_count++; - is_suspicious = 1; - } + // Git-Repository Zugriffe (häufig bei Recon) + if (search_in_string(all_entries[i].url_path, ".git/") || + search_in_string(all_entries[i].url_path, "/.git")) { + annotate_entry(i, "Git Access"); + suspicious_patterns_count++; + } + + // Environment-Dateien (kritische Konfigurationsdateien) + if (search_in_string(all_entries[i].url_path, ".env") || + search_in_string(all_entries[i].url_path, ".config") || + search_in_string(all_entries[i].url_path, "config.php")) { + annotate_entry(i, "Config Access"); + suspicious_patterns_count++; + } + + // WordPress Admin-Bereiche (häufig attackiert) + if (search_in_string(all_entries[i].url_path, "wp-admin") || + search_in_string(all_entries[i].url_path, "wp-login") || + search_in_string(all_entries[i].url_path, "wp-config")) { + annotate_entry(i, "WP Attack"); + suspicious_patterns_count++; + } + + // Database Management Tools + if (search_in_string(all_entries[i].url_path, "phpmyadmin") || + search_in_string(all_entries[i].url_path, "phpMyAdmin") || + search_in_string(all_entries[i].url_path, "adminer")) { + annotate_entry(i, "DB Tool Access"); + suspicious_patterns_count++; + } + + // Admin/Management Interfaces + if (search_in_string(all_entries[i].url_path, "/admin") || + search_in_string(all_entries[i].url_path, "/manager") || + search_in_string(all_entries[i].url_path, "/console")) { + annotate_entry(i, "Admin Access"); + suspicious_patterns_count++; } // 3. DIRECTORY TRAVERSAL: Pfad-Traversal Versuche - if (!is_suspicious) { - if (search_in_string(all_entries[i].url_path, "../") || - search_in_string(all_entries[i].url_path, "..\\") || - search_in_string(all_entries[i].url_path, "%2e%2e%2f") || - search_in_string(all_entries[i].url_path, "%2e%2e%5c")) { - annotate_entry(i, "Path Traversal"); - suspicious_patterns_count++; - is_suspicious = 1; - } + if (search_in_string(all_entries[i].url_path, "../") || + search_in_string(all_entries[i].url_path, "..\\") || + search_in_string(all_entries[i].url_path, "%2e%2e%2f") || + search_in_string(all_entries[i].url_path, "%2e%2e%5c")) { + annotate_entry(i, "Path Traversal"); + suspicious_patterns_count++; } // 4. SQL INJECTION: SQL-Keywords in URLs - if (!is_suspicious) { - if (search_in_string(all_entries[i].url_path, "select%20") || - search_in_string(all_entries[i].url_path, "union%20") || - search_in_string(all_entries[i].url_path, "insert%20") || - search_in_string(all_entries[i].url_path, "delete%20") || - search_in_string(all_entries[i].url_path, "drop%20") || - search_in_string(all_entries[i].url_path, "' or ") || - search_in_string(all_entries[i].url_path, "' and ") || - search_in_string(all_entries[i].url_path, "1=1") || - search_in_string(all_entries[i].url_path, "1' or '1'='1")) { - annotate_entry(i, "SQL Injection"); - suspicious_patterns_count++; - is_suspicious = 1; - } + if (search_in_string(all_entries[i].url_path, "select%20") || + search_in_string(all_entries[i].url_path, "union%20") || + search_in_string(all_entries[i].url_path, "insert%20") || + search_in_string(all_entries[i].url_path, "delete%20") || + search_in_string(all_entries[i].url_path, "drop%20") || + search_in_string(all_entries[i].url_path, "' or ") || + search_in_string(all_entries[i].url_path, "' and ") || + search_in_string(all_entries[i].url_path, "1=1") || + search_in_string(all_entries[i].url_path, "1' or '1'='1")) { + annotate_entry(i, "SQL Injection"); + suspicious_patterns_count++; } // 5. XSS ATTEMPTS: Cross-Site-Scripting Versuche - if (!is_suspicious) { - if (search_in_string(all_entries[i].url_path, " 10) { - annotate_entry(i, "Heavy Encoding"); - suspicious_patterns_count++; - is_suspicious = 1; - } + char *url = all_entries[i].url_path; + int encoding_count = 0; + char *pos = url; + while ((pos = strstr(pos, "%")) != NULL) { + encoding_count++; + pos++; + } + // Wenn mehr als 10 URL-Encodings in einer URL, verdächtig + if (encoding_count > 10) { + annotate_entry(i, "Heavy Encoding"); + suspicious_patterns_count++; } // 9. ATYPICAL HTTP METHODS: Ungewöhnliche oder fehlerhafte HTTP-Methoden - if (!is_suspicious) { - if (strcmp(all_entries[i].request_method, "ATYPICAL") == 0) { - annotate_entry(i, "Malformed Request"); - suspicious_patterns_count++; - is_suspicious = 1; - } - // Seltene aber potentiell gefährliche HTTP-Methoden - else if (strcmp(all_entries[i].request_method, "PROPFIND") == 0 || - strcmp(all_entries[i].request_method, "MKCOL") == 0 || - strcmp(all_entries[i].request_method, "COPY") == 0 || - strcmp(all_entries[i].request_method, "MOVE") == 0 || - strcmp(all_entries[i].request_method, "LOCK") == 0) { - annotate_entry(i, "Rare Method"); - suspicious_patterns_count++; - is_suspicious = 1; - } + if (strcmp(all_entries[i].request_method, "ATYPICAL") == 0) { + annotate_entry(i, "Malformed Request"); + suspicious_patterns_count++; + } + // Seltene aber potentiell gefährliche HTTP-Methoden + else if (strcmp(all_entries[i].request_method, "PROPFIND") == 0 || + strcmp(all_entries[i].request_method, "MKCOL") == 0 || + strcmp(all_entries[i].request_method, "COPY") == 0 || + strcmp(all_entries[i].request_method, "MOVE") == 0 || + strcmp(all_entries[i].request_method, "LOCK") == 0) { + annotate_entry(i, "Rare Method"); + suspicious_patterns_count++; } // 10. STATUS CODE ANOMALIES: Verdächtige Status-Code Muster - if (!is_suspicious) { - // 403 auf sensible Pfade könnte Angriffserkennung bedeuten - if (all_entries[i].status_code == 403 && - (search_in_string(all_entries[i].url_path, "admin") || - search_in_string(all_entries[i].url_path, ".git") || - search_in_string(all_entries[i].url_path, ".env"))) { - annotate_entry(i, "Blocked Access"); - suspicious_patterns_count++; - is_suspicious = 1; - } - // 429 Too Many Requests - Rate Limiting aktiviert - else if (all_entries[i].status_code == 429) { - annotate_entry(i, "Rate Limited"); - suspicious_patterns_count++; - is_suspicious = 1; - } + // 403 auf sensible Pfade könnte Angriffserkennung bedeuten + if (all_entries[i].status_code == 403 && + (search_in_string(all_entries[i].url_path, "admin") || + search_in_string(all_entries[i].url_path, ".git") || + search_in_string(all_entries[i].url_path, ".env"))) { + annotate_entry(i, "Blocked Access"); + suspicious_patterns_count++; + } + // 429 Too Many Requests - Rate Limiting aktiviert + if (all_entries[i].status_code == 429) { + annotate_entry(i, "Rate Limited"); + suspicious_patterns_count++; } // 11. CREDENTIAL STUFFING: Wiederholte Login-Versuche mit verschiedenen Credentials - if (!is_suspicious) { - if ((search_in_string(all_entries[i].url_path, "login") || - search_in_string(all_entries[i].url_path, "signin") || - search_in_string(all_entries[i].url_path, "auth")) && - (all_entries[i].status_code == 401 || all_entries[i].status_code == 403)) { - annotate_entry(i, "Failed Auth"); - suspicious_patterns_count++; - is_suspicious = 1; - } + if ((search_in_string(all_entries[i].url_path, "login") || + search_in_string(all_entries[i].url_path, "signin") || + search_in_string(all_entries[i].url_path, "auth")) && + (all_entries[i].status_code == 401 || all_entries[i].status_code == 403)) { + annotate_entry(i, "Failed Auth"); + suspicious_patterns_count++; } // 12. SHELL/WEBSHELL ACCESS: Verdächtige Shell-bezogene Pfade - if (!is_suspicious) { - if (search_in_string(all_entries[i].url_path, ".php?") || - search_in_string(all_entries[i].url_path, "shell") || - search_in_string(all_entries[i].url_path, "backdoor") || - search_in_string(all_entries[i].url_path, "cmd=") || - search_in_string(all_entries[i].url_path, "exec=") || - search_in_string(all_entries[i].url_path, "system=")) { - annotate_entry(i, "Shell Access"); - suspicious_patterns_count++; - is_suspicious = 1; - } + if (search_in_string(all_entries[i].url_path, ".php?") || + search_in_string(all_entries[i].url_path, "shell") || + search_in_string(all_entries[i].url_path, "backdoor") || + search_in_string(all_entries[i].url_path, "cmd=") || + search_in_string(all_entries[i].url_path, "exec=") || + search_in_string(all_entries[i].url_path, "system=")) { + annotate_entry(i, "Shell Access"); + suspicious_patterns_count++; } // 13. API ABUSE: Verdächtige API-Zugriffe - if (!is_suspicious) { - if (search_in_string(all_entries[i].url_path, "/api/") && - (all_entries[i].status_code >= 400 && all_entries[i].status_code < 500)) { - annotate_entry(i, "API Error"); - suspicious_patterns_count++; - is_suspicious = 1; - } + if (search_in_string(all_entries[i].url_path, "/api/") && + (all_entries[i].status_code >= 400 && all_entries[i].status_code < 500)) { + annotate_entry(i, "API Error"); + suspicious_patterns_count++; } } @@ -1382,8 +1342,20 @@ void format_iso8601_time(struct simple_time time, char* buffer, int buffer_size) } //Export in Timesketch-kompatiblem Format +void write_csv_field(FILE* file, const char* field) { + fprintf(file, "\""); + for (const char* p = field; *p; p++) { + if (*p == '"') { + fprintf(file, "\"\""); + } else { + fprintf(file, "%c", *p); + } + } + fprintf(file, "\""); +} + void export_filtered_entries(char *filepath) { - //90 chars + delimiter + // 90 chars +delimiter char filename[91]; if (filepath == NULL) { printf("Dateiname für Timesketch-Export eingeben (ohne .csv): "); @@ -1396,7 +1368,7 @@ void export_filtered_entries(char *filepath) { strncpy(filename, filepath, sizeof(filename) - 1); filename[sizeof(filename) - 1] = '\0'; } - // Dateiendung + strcat(filename, ".csv"); printf("\nINFO: Schreibe Datei %s...\n", filename); FILE* file = fopen(filename, "w"); @@ -1415,44 +1387,56 @@ void export_filtered_entries(char *filepath) { if (passes_filter(i)) { format_iso8601_time(all_entries[i].time, iso_datetime, sizeof(iso_datetime)); - // https://stackoverflow.com/questions/5901181/c-string-append - // https://www.quora.com/How-can-we-count-the-number-of-special-characters-in-a-string-in-the-C-language-using-fgets - char* tag_str; - int num_delimiters = 0; - int c=0; - while(all_entries[i].annotation[c]!='\0'){ - num_delimiters++; - } - if (tag_str=malloc(sizeof(all_entries[i].annotation)+sizeof("[ ]")+(sizeof(','))*num_delimiters)+1)!=NULL){ - tag_str[0] = '\0'; + // Tags werden von Timesketch in diesem Format erwartet: [ "tag1","tag2" ] + char tag_str[256] = ""; + if (strlen(all_entries[i].annotation) > 0) { + // Create a working copy for strtok (it modifies the string) + char annotation_copy[64]; + strncpy(annotation_copy, all_entries[i].annotation, sizeof(annotation_copy) - 1); + annotation_copy[sizeof(annotation_copy) - 1] = '\0'; - - char* token = strtok(all_entries[i].annotation, ","); - if (!token) return; strcat(tag_str, "[ "); - for (i=0;i