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
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, "<script") ||
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, "onerror=") ||
search_in_string(all_entries[i].url_path, "onload=") ||
search_in_string(all_entries[i].url_path, "alert(")) {
annotate_entry(i, "XSS Attempt");
suspicious_patterns_count++;
is_suspicious = 1;
}
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, "javascript:") ||
search_in_string(all_entries[i].url_path, "onerror=") ||
search_in_string(all_entries[i].url_path, "onload=") ||
search_in_string(all_entries[i].url_path, "alert(")) {
annotate_entry(i, "XSS Attempt");
suspicious_patterns_count++;
}
// 6. BACKUP/SENSITIVE FILE ACCESS: Backup-Dateien und sensible Extensions
if (!is_suspicious) {
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, ".backup") ||
search_in_string(all_entries[i].url_path, ".sql") ||
search_in_string(all_entries[i].url_path, ".log") ||
search_in_string(all_entries[i].url_path, ".key") ||
search_in_string(all_entries[i].url_path, ".pem")) {
annotate_entry(i, "Sensitive File");
suspicious_patterns_count++;
is_suspicious = 1;
}
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, ".backup") ||
search_in_string(all_entries[i].url_path, ".sql") ||
search_in_string(all_entries[i].url_path, ".log") ||
search_in_string(all_entries[i].url_path, ".key") ||
search_in_string(all_entries[i].url_path, ".pem")) {
annotate_entry(i, "Sensitive File");
suspicious_patterns_count++;
}
// 7. BOT/SCANNER DETECTION: Verdächtige User-Agents
if (!is_suspicious) {
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, "nikto") ||
search_in_string(all_entries[i].user_agent, "dirb") ||
search_in_string(all_entries[i].user_agent, "gobuster") ||
search_in_string(all_entries[i].user_agent, "whatweb") ||
search_in_string(all_entries[i].user_agent, "masscan") ||
search_in_string(all_entries[i].user_agent, "python-requests") ||
search_in_string(all_entries[i].user_agent, "curl/") ||
search_in_string(all_entries[i].user_agent, "wget/")) {
annotate_entry(i, "Scanner/Bot");
suspicious_patterns_count++;
is_suspicious = 1;
}
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, "nikto") ||
search_in_string(all_entries[i].user_agent, "dirb") ||
search_in_string(all_entries[i].user_agent, "gobuster") ||
search_in_string(all_entries[i].user_agent, "whatweb") ||
search_in_string(all_entries[i].user_agent, "masscan") ||
search_in_string(all_entries[i].user_agent, "python-requests") ||
search_in_string(all_entries[i].user_agent, "curl/") ||
search_in_string(all_entries[i].user_agent, "wget/")) {
annotate_entry(i, "Scanner/Bot");
suspicious_patterns_count++;
}
// 8. EXCESSIVE URL ENCODING: Verdächtig hohe Anzahl von URL-Encoding
if (!is_suspicious) {
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++;
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<num_delimiters;i++){
// 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* token = strtok(annotation_copy, ",");
int first = 1;
while (token != NULL) {
if (!first) {
strcat(tag_str, ",");
}
strcat(tag_str, "\"");
strcat(tag_str, strtok(NULL, ","));
strcat(tag_str, '"');
strncat(tag_str, token, sizeof(tag_str) - strlen(tag_str) - 3);
strcat(tag_str, "\"");
first = 0;
token = strtok(NULL, ",");
}
strcat(tag_str, " ]");
}
fprintf(file, "\"%s\",\"%s\",\"HTTP Access Log\",\"%s\",\"%s\",\"%s\",%d,%d,\"%s\",\"%s\",\"%s\"\n",
iso_datetime, // datetime
all_entries[i].source_file, // message
all_entries[i].ip_address,
all_entries[i].request_method,
all_entries[i].url_path,
all_entries[i].status_code,
all_entries[i].bytes_sent,
all_entries[i].user_agent,
all_entries[i].parsing_timestamp,
tag_str
//all_entries[i].annotation // tag
);
free(tag_str);
tag_str=NULL;
// Write CSV row with proper escaping
write_csv_field(file, iso_datetime);
fprintf(file, ",");
write_csv_field(file, all_entries[i].source_file);
fprintf(file, ",");
write_csv_field(file, "HTTP Access Log");
fprintf(file, ",");
write_csv_field(file, all_entries[i].ip_address);
fprintf(file, ",");
write_csv_field(file, all_entries[i].request_method);
fprintf(file, ",");
write_csv_field(file, all_entries[i].url_path);
fprintf(file, ",");
fprintf(file, "%d", all_entries[i].status_code);
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++;
}
}
@ -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("\nCSV-Export (Timesketch-kompatibel):\n");
printf(" Spalten: datetime, timestamp_desc, ip_address, method, url_path, status_code,\n");
printf(" bytes_sent, user_agent, source_file, parsing_timestamp, annotation\n");
printf(" Spalten: datetime, message timestamp_desc, ip_address, method, url_path, status_code,\n");
printf(" bytes_sent, user_agent, source_file, parsing_timestamp, tag\n");
printf("\nAnnotationen:\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(" - 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(" - Komplexe Zeitraum-Filter sind vollständig über Kommandozeile verfügbar.\n");
}
int main(int argc, char* argv[]) {