This commit is contained in:
overcuriousity 2025-09-05 14:01:59 +02:00
parent 80504583a4
commit d3b949949c

View File

@ -384,7 +384,7 @@ int search_in_string(char* raw_string, char* search_string) {
// https://stackoverflow.com/questions/5901181/c-string-append // https://stackoverflow.com/questions/5901181/c-string-append
void annotate_entry(int index, char* annotation_string) { void annotate_entry(int index, char* annotation_string) {
if (index >= 0 && index < total_entries) { 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); 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].annotation[sizeof(all_entries[index].annotation) - 1] = '\0';
all_entries[index].annotated_flag = 1; all_entries[index].annotated_flag = 1;
@ -392,6 +392,7 @@ void annotate_entry(int index, char* annotation_string) {
char * new_str ; char * new_str ;
if((new_str = malloc(strlen(all_entries[index].annotation)+strlen(",")+strlen(annotation_string)+1)) != NULL){ 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 new_str[0] = '\0'; // ensures the memory is an empty string
strcat(new_str, all_entries[index].annotation);
strcat(new_str, ","); strcat(new_str, ",");
strcat(new_str, annotation_string); strcat(new_str, annotation_string);
strncpy(all_entries[index].annotation, new_str, sizeof(all_entries[index].annotation) - 1); strncpy(all_entries[index].annotation, new_str, sizeof(all_entries[index].annotation) - 1);
@ -415,73 +416,63 @@ void annotate_suspicious_entries(struct log_entry* dataset) {
all_entries[i].annotation[0] = '\0'; all_entries[i].annotation[0] = '\0';
} }
int is_suspicious = 0; // Flag um zu verfolgen ob bereits annotiert // 1. PAYLOAD-GRÖßE: Sehr lange Requests
// 1. PAYLOAD-GRÖßE: Sehr lange Requests (bereits vorhanden, aber verbessert)
int url_length = strlen(all_entries[i].url_path); int url_length = strlen(all_entries[i].url_path);
if (url_length > SUSPICIOUS_REQUEST_LEN_THRESHOLD) { if (url_length > SUSPICIOUS_REQUEST_LEN_THRESHOLD) {
annotate_entry(i, "Long Payload"); annotate_entry(i, "Long Payload");
suspicious_patterns_count++; suspicious_patterns_count++;
is_suspicious = 1;
} }
// 2. PFAD-BASIERTE ANGRIFFE: Häufige Angriffsziele und sensible Pfade // 2. PFAD-BASIERTE ANGRIFFE: Häufige Angriffsziele und sensible Pfade
if (!is_suspicious) {
// Git-Repository Zugriffe (häufig bei Recon) // Git-Repository Zugriffe (häufig bei Recon)
if (search_in_string(all_entries[i].url_path, ".git/") || if (search_in_string(all_entries[i].url_path, ".git/") ||
search_in_string(all_entries[i].url_path, "/.git")) { search_in_string(all_entries[i].url_path, "/.git")) {
annotate_entry(i, "Git Access"); annotate_entry(i, "Git Access");
suspicious_patterns_count++; suspicious_patterns_count++;
is_suspicious = 1;
} }
// Environment-Dateien (kritische Konfigurationsdateien) // Environment-Dateien (kritische Konfigurationsdateien)
else if (search_in_string(all_entries[i].url_path, ".env") || 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") ||
search_in_string(all_entries[i].url_path, "config.php")) { search_in_string(all_entries[i].url_path, "config.php")) {
annotate_entry(i, "Config Access"); annotate_entry(i, "Config Access");
suspicious_patterns_count++; suspicious_patterns_count++;
is_suspicious = 1;
} }
// WordPress Admin-Bereiche (häufig attackiert) // WordPress Admin-Bereiche (häufig attackiert)
else if (search_in_string(all_entries[i].url_path, "wp-admin") || 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-login") ||
search_in_string(all_entries[i].url_path, "wp-config")) { search_in_string(all_entries[i].url_path, "wp-config")) {
annotate_entry(i, "WP Attack"); annotate_entry(i, "WP Attack");
suspicious_patterns_count++; suspicious_patterns_count++;
is_suspicious = 1;
} }
// Database Management Tools // Database Management Tools
else if (search_in_string(all_entries[i].url_path, "phpmyadmin") || 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, "phpMyAdmin") ||
search_in_string(all_entries[i].url_path, "adminer")) { search_in_string(all_entries[i].url_path, "adminer")) {
annotate_entry(i, "DB Tool Access"); annotate_entry(i, "DB Tool Access");
suspicious_patterns_count++; suspicious_patterns_count++;
is_suspicious = 1;
} }
// Admin/Management Interfaces // Admin/Management Interfaces
else if (search_in_string(all_entries[i].url_path, "/admin") || 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, "/manager") ||
search_in_string(all_entries[i].url_path, "/console")) { search_in_string(all_entries[i].url_path, "/console")) {
annotate_entry(i, "Admin Access"); annotate_entry(i, "Admin Access");
suspicious_patterns_count++; suspicious_patterns_count++;
is_suspicious = 1;
}
} }
// 3. DIRECTORY TRAVERSAL: Pfad-Traversal Versuche // 3. DIRECTORY TRAVERSAL: Pfad-Traversal Versuche
if (!is_suspicious) {
if (search_in_string(all_entries[i].url_path, "../") || 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, "..\\") ||
search_in_string(all_entries[i].url_path, "%2e%2e%2f") || search_in_string(all_entries[i].url_path, "%2e%2e%2f") ||
search_in_string(all_entries[i].url_path, "%2e%2e%5c")) { search_in_string(all_entries[i].url_path, "%2e%2e%5c")) {
annotate_entry(i, "Path Traversal"); annotate_entry(i, "Path Traversal");
suspicious_patterns_count++; suspicious_patterns_count++;
is_suspicious = 1;
}
} }
// 4. SQL INJECTION: SQL-Keywords in URLs // 4. SQL INJECTION: SQL-Keywords in URLs
if (!is_suspicious) {
if (search_in_string(all_entries[i].url_path, "select%20") || 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, "union%20") ||
search_in_string(all_entries[i].url_path, "insert%20") || search_in_string(all_entries[i].url_path, "insert%20") ||
@ -493,12 +484,9 @@ void annotate_suspicious_entries(struct log_entry* dataset) {
search_in_string(all_entries[i].url_path, "1' or '1'='1")) { search_in_string(all_entries[i].url_path, "1' or '1'='1")) {
annotate_entry(i, "SQL Injection"); annotate_entry(i, "SQL Injection");
suspicious_patterns_count++; suspicious_patterns_count++;
is_suspicious = 1;
}
} }
// 5. XSS ATTEMPTS: Cross-Site-Scripting Versuche // 5. XSS ATTEMPTS: Cross-Site-Scripting Versuche
if (!is_suspicious) {
if (search_in_string(all_entries[i].url_path, "<script") || if (search_in_string(all_entries[i].url_path, "<script") ||
search_in_string(all_entries[i].url_path, "%3cscript") || search_in_string(all_entries[i].url_path, "%3cscript") ||
search_in_string(all_entries[i].url_path, "javascript:") || search_in_string(all_entries[i].url_path, "javascript:") ||
@ -507,12 +495,9 @@ void annotate_suspicious_entries(struct log_entry* dataset) {
search_in_string(all_entries[i].url_path, "alert(")) { search_in_string(all_entries[i].url_path, "alert(")) {
annotate_entry(i, "XSS Attempt"); annotate_entry(i, "XSS Attempt");
suspicious_patterns_count++; suspicious_patterns_count++;
is_suspicious = 1;
}
} }
// 6. BACKUP/SENSITIVE FILE ACCESS: Backup-Dateien und sensible Extensions // 6. BACKUP/SENSITIVE FILE ACCESS: Backup-Dateien und sensible Extensions
if (!is_suspicious) {
if (search_in_string(all_entries[i].url_path, ".bak") || if (search_in_string(all_entries[i].url_path, ".bak") ||
search_in_string(all_entries[i].url_path, ".old") || search_in_string(all_entries[i].url_path, ".old") ||
search_in_string(all_entries[i].url_path, ".backup") || search_in_string(all_entries[i].url_path, ".backup") ||
@ -522,12 +507,9 @@ void annotate_suspicious_entries(struct log_entry* dataset) {
search_in_string(all_entries[i].url_path, ".pem")) { search_in_string(all_entries[i].url_path, ".pem")) {
annotate_entry(i, "Sensitive File"); annotate_entry(i, "Sensitive File");
suspicious_patterns_count++; suspicious_patterns_count++;
is_suspicious = 1;
}
} }
// 7. BOT/SCANNER DETECTION: Verdächtige User-Agents // 7. BOT/SCANNER DETECTION: Verdächtige User-Agents
if (!is_suspicious) {
if (search_in_string(all_entries[i].user_agent, "nmap") || if (search_in_string(all_entries[i].user_agent, "nmap") ||
search_in_string(all_entries[i].user_agent, "sqlmap") || search_in_string(all_entries[i].user_agent, "sqlmap") ||
search_in_string(all_entries[i].user_agent, "nikto") || search_in_string(all_entries[i].user_agent, "nikto") ||
@ -540,12 +522,9 @@ void annotate_suspicious_entries(struct log_entry* dataset) {
search_in_string(all_entries[i].user_agent, "wget/")) { search_in_string(all_entries[i].user_agent, "wget/")) {
annotate_entry(i, "Scanner/Bot"); annotate_entry(i, "Scanner/Bot");
suspicious_patterns_count++; suspicious_patterns_count++;
is_suspicious = 1;
}
} }
// 8. EXCESSIVE URL ENCODING: Verdächtig hohe Anzahl von URL-Encoding // 8. EXCESSIVE URL ENCODING: Verdächtig hohe Anzahl von URL-Encoding
if (!is_suspicious) {
char *url = all_entries[i].url_path; char *url = all_entries[i].url_path;
int encoding_count = 0; int encoding_count = 0;
char *pos = url; char *pos = url;
@ -557,16 +536,12 @@ void annotate_suspicious_entries(struct log_entry* dataset) {
if (encoding_count > 10) { if (encoding_count > 10) {
annotate_entry(i, "Heavy Encoding"); annotate_entry(i, "Heavy Encoding");
suspicious_patterns_count++; suspicious_patterns_count++;
is_suspicious = 1;
}
} }
// 9. ATYPICAL HTTP METHODS: Ungewöhnliche oder fehlerhafte HTTP-Methoden // 9. ATYPICAL HTTP METHODS: Ungewöhnliche oder fehlerhafte HTTP-Methoden
if (!is_suspicious) {
if (strcmp(all_entries[i].request_method, "ATYPICAL") == 0) { if (strcmp(all_entries[i].request_method, "ATYPICAL") == 0) {
annotate_entry(i, "Malformed Request"); annotate_entry(i, "Malformed Request");
suspicious_patterns_count++; suspicious_patterns_count++;
is_suspicious = 1;
} }
// Seltene aber potentiell gefährliche HTTP-Methoden // Seltene aber potentiell gefährliche HTTP-Methoden
else if (strcmp(all_entries[i].request_method, "PROPFIND") == 0 || else if (strcmp(all_entries[i].request_method, "PROPFIND") == 0 ||
@ -576,12 +551,9 @@ void annotate_suspicious_entries(struct log_entry* dataset) {
strcmp(all_entries[i].request_method, "LOCK") == 0) { strcmp(all_entries[i].request_method, "LOCK") == 0) {
annotate_entry(i, "Rare Method"); annotate_entry(i, "Rare Method");
suspicious_patterns_count++; suspicious_patterns_count++;
is_suspicious = 1;
}
} }
// 10. STATUS CODE ANOMALIES: Verdächtige Status-Code Muster // 10. STATUS CODE ANOMALIES: Verdächtige Status-Code Muster
if (!is_suspicious) {
// 403 auf sensible Pfade könnte Angriffserkennung bedeuten // 403 auf sensible Pfade könnte Angriffserkennung bedeuten
if (all_entries[i].status_code == 403 && if (all_entries[i].status_code == 403 &&
(search_in_string(all_entries[i].url_path, "admin") || (search_in_string(all_entries[i].url_path, "admin") ||
@ -589,30 +561,23 @@ void annotate_suspicious_entries(struct log_entry* dataset) {
search_in_string(all_entries[i].url_path, ".env"))) { search_in_string(all_entries[i].url_path, ".env"))) {
annotate_entry(i, "Blocked Access"); annotate_entry(i, "Blocked Access");
suspicious_patterns_count++; suspicious_patterns_count++;
is_suspicious = 1;
} }
// 429 Too Many Requests - Rate Limiting aktiviert // 429 Too Many Requests - Rate Limiting aktiviert
else if (all_entries[i].status_code == 429) { if (all_entries[i].status_code == 429) {
annotate_entry(i, "Rate Limited"); annotate_entry(i, "Rate Limited");
suspicious_patterns_count++; suspicious_patterns_count++;
is_suspicious = 1;
}
} }
// 11. CREDENTIAL STUFFING: Wiederholte Login-Versuche mit verschiedenen Credentials // 11. CREDENTIAL STUFFING: Wiederholte Login-Versuche mit verschiedenen Credentials
if (!is_suspicious) {
if ((search_in_string(all_entries[i].url_path, "login") || 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, "signin") ||
search_in_string(all_entries[i].url_path, "auth")) && search_in_string(all_entries[i].url_path, "auth")) &&
(all_entries[i].status_code == 401 || all_entries[i].status_code == 403)) { (all_entries[i].status_code == 401 || all_entries[i].status_code == 403)) {
annotate_entry(i, "Failed Auth"); annotate_entry(i, "Failed Auth");
suspicious_patterns_count++; suspicious_patterns_count++;
is_suspicious = 1;
}
} }
// 12. SHELL/WEBSHELL ACCESS: Verdächtige Shell-bezogene Pfade // 12. SHELL/WEBSHELL ACCESS: Verdächtige Shell-bezogene Pfade
if (!is_suspicious) {
if (search_in_string(all_entries[i].url_path, ".php?") || 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, "shell") ||
search_in_string(all_entries[i].url_path, "backdoor") || search_in_string(all_entries[i].url_path, "backdoor") ||
@ -621,18 +586,13 @@ void annotate_suspicious_entries(struct log_entry* dataset) {
search_in_string(all_entries[i].url_path, "system=")) { search_in_string(all_entries[i].url_path, "system=")) {
annotate_entry(i, "Shell Access"); annotate_entry(i, "Shell Access");
suspicious_patterns_count++; suspicious_patterns_count++;
is_suspicious = 1;
}
} }
// 13. API ABUSE: Verdächtige API-Zugriffe // 13. API ABUSE: Verdächtige API-Zugriffe
if (!is_suspicious) {
if (search_in_string(all_entries[i].url_path, "/api/") && if (search_in_string(all_entries[i].url_path, "/api/") &&
(all_entries[i].status_code >= 400 && all_entries[i].status_code < 500)) { (all_entries[i].status_code >= 400 && all_entries[i].status_code < 500)) {
annotate_entry(i, "API Error"); annotate_entry(i, "API Error");
suspicious_patterns_count++; suspicious_patterns_count++;
is_suspicious = 1;
}
} }
} }
@ -1382,6 +1342,18 @@ void format_iso8601_time(struct simple_time time, char* buffer, int buffer_size)
} }
//Export in Timesketch-kompatiblem Format //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) { void export_filtered_entries(char *filepath) {
// 90 chars +delimiter // 90 chars +delimiter
char filename[91]; char filename[91];
@ -1396,7 +1368,7 @@ void export_filtered_entries(char *filepath) {
strncpy(filename, filepath, sizeof(filename) - 1); strncpy(filename, filepath, sizeof(filename) - 1);
filename[sizeof(filename) - 1] = '\0'; filename[sizeof(filename) - 1] = '\0';
} }
// Dateiendung
strcat(filename, ".csv"); strcat(filename, ".csv");
printf("\nINFO: Schreibe Datei %s...\n", filename); printf("\nINFO: Schreibe Datei %s...\n", filename);
FILE* file = fopen(filename, "w"); FILE* file = fopen(filename, "w");
@ -1415,44 +1387,56 @@ void export_filtered_entries(char *filepath) {
if (passes_filter(i)) { if (passes_filter(i)) {
format_iso8601_time(all_entries[i].time, iso_datetime, sizeof(iso_datetime)); format_iso8601_time(all_entries[i].time, iso_datetime, sizeof(iso_datetime));
// 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';
strcat(tag_str, "[ ");
// https://stackoverflow.com/questions/5901181/c-string-append // 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 // 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; char* token = strtok(annotation_copy, ",");
int num_delimiters = 0; int first = 1;
int c=0; while (token != NULL) {
while(all_entries[i].annotation[c]!='\0'){ if (!first) {
num_delimiters++; strcat(tag_str, ",");
} }
if (tag_str=malloc(sizeof(all_entries[i].annotation)+sizeof("[ ]")+(sizeof(','))*num_delimiters)+1)!=NULL){
tag_str[0] = '\0';
char* token = strtok(all_entries[i].annotation, ",");
if (!token) return;
strcat(tag_str, "[ ");
for (i=0;i<num_delimiters;i++){
strcat(tag_str, "\""); strcat(tag_str, "\"");
strcat(tag_str, strtok(NULL, ",")); strncat(tag_str, token, sizeof(tag_str) - strlen(tag_str) - 3);
strcat(tag_str, '"'); strcat(tag_str, "\"");
first = 0;
token = strtok(NULL, ",");
} }
strcat(tag_str, " ]"); strcat(tag_str, " ]");
} }
fprintf(file, "\"%s\",\"%s\",\"HTTP Access Log\",\"%s\",\"%s\",\"%s\",%d,%d,\"%s\",\"%s\",\"%s\"\n", // Write CSV row with proper escaping
iso_datetime, // datetime write_csv_field(file, iso_datetime);
all_entries[i].source_file, // message fprintf(file, ",");
all_entries[i].ip_address, write_csv_field(file, all_entries[i].source_file);
all_entries[i].request_method, fprintf(file, ",");
all_entries[i].url_path, write_csv_field(file, "HTTP Access Log");
all_entries[i].status_code, fprintf(file, ",");
all_entries[i].bytes_sent, write_csv_field(file, all_entries[i].ip_address);
all_entries[i].user_agent, fprintf(file, ",");
all_entries[i].parsing_timestamp, write_csv_field(file, all_entries[i].request_method);
tag_str fprintf(file, ",");
//all_entries[i].annotation // tag write_csv_field(file, all_entries[i].url_path);
); fprintf(file, ",");
free(tag_str); fprintf(file, "%d", all_entries[i].status_code);
tag_str=NULL; fprintf(file, ",");
fprintf(file, "%d", all_entries[i].bytes_sent);
fprintf(file, ",");
write_csv_field(file, all_entries[i].user_agent);
fprintf(file, ",");
write_csv_field(file, all_entries[i].parsing_timestamp);
fprintf(file, ",");
write_csv_field(file, tag_str);
fprintf(file, "\n");
exported_count++; exported_count++;
} }
} }
@ -3033,8 +3017,8 @@ void print_help(char* binary) {
printf(" 0.0.0.0 - - [31/Aug/2025:00:11:42 +0000] \"GET /.git/config HTTP/1.1\" 400 255 \"-\" \"Mozilla/5.0\" \"-\"\n"); printf(" 0.0.0.0 - - [31/Aug/2025:00:11:42 +0000] \"GET /.git/config HTTP/1.1\" 400 255 \"-\" \"Mozilla/5.0\" \"-\"\n");
printf("\nCSV-Export (Timesketch-kompatibel):\n"); printf("\nCSV-Export (Timesketch-kompatibel):\n");
printf(" Spalten: datetime, timestamp_desc, ip_address, method, url_path, status_code,\n"); printf(" Spalten: datetime, message timestamp_desc, ip_address, method, url_path, status_code,\n");
printf(" bytes_sent, user_agent, source_file, parsing_timestamp, annotation\n"); printf(" bytes_sent, user_agent, source_file, parsing_timestamp, tag\n");
printf("\nAnnotationen:\n"); printf("\nAnnotationen:\n");
printf(" - Automatische Erkennung verdächtiger Muster (z.B. 'Long Payload')\n"); printf(" - Automatische Erkennung verdächtiger Muster (z.B. 'Long Payload')\n");
@ -3045,7 +3029,6 @@ void print_help(char* binary) {
printf(" - Parser erwartet das obige Standardformat. Abweichungen können zum Abbruch führen.\n"); printf(" - Parser erwartet das obige Standardformat. Abweichungen können zum Abbruch führen.\n");
printf(" - Zeitzone aus dem Log wird gelesen, aber intern als einfache Felder verarbeitet.\n"); printf(" - Zeitzone aus dem Log wird gelesen, aber intern als einfache Felder verarbeitet.\n");
printf(" - ATYPICAL-Methode: für fehlerhafte/binäre Requests innerhalb der \"request\"-Spalte.\n"); printf(" - ATYPICAL-Methode: für fehlerhafte/binäre Requests innerhalb der \"request\"-Spalte.\n");
printf(" - Komplexe Zeitraum-Filter sind vollständig über Kommandozeile verfügbar.\n");
} }
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {