progress
This commit is contained in:
parent
d654e32e8a
commit
6b2e4b4373
278
src/main.c
278
src/main.c
@ -24,6 +24,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|||||||
#include <sys/stat.h> // library für is_directory: Unterscheidung zwischen Dateien und Ordnern
|
#include <sys/stat.h> // library für is_directory: Unterscheidung zwischen Dateien und Ordnern
|
||||||
#include <time.h> // um aktuelle Zeit zu generieren
|
#include <time.h> // um aktuelle Zeit zu generieren
|
||||||
#include "gzunpack.h"
|
#include "gzunpack.h"
|
||||||
|
#include "suspicious_detection.h"
|
||||||
|
|
||||||
#define INITIAL_ENTRIES 1000 // globale Variable zur initialen Speicherallokation in allocate_initial_memory(). Wird falls nötig um GROWTH_FACTOR erweitert
|
#define INITIAL_ENTRIES 1000 // globale Variable zur initialen Speicherallokation in allocate_initial_memory(). Wird falls nötig um GROWTH_FACTOR erweitert
|
||||||
#define GROWTH_FACTOR 1.1 // wird in mem_expand_dynamically() genutzt, um den Speicher zu vergrößern
|
#define GROWTH_FACTOR 1.1 // wird in mem_expand_dynamically() genutzt, um den Speicher zu vergrößern
|
||||||
@ -102,7 +103,7 @@ struct url_filter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct annotation_flag_filter {
|
struct annotation_flag_filter {
|
||||||
int annotation_flag_is_set;
|
int annotation_flag_is_present;
|
||||||
filter_mode_t mode;
|
filter_mode_t mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -341,6 +342,7 @@ void annotate_entry(int index, char* annotation_string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Muster hier KI-generiert.
|
||||||
void annotate_suspicious_entries(struct log_entry* dataset) {
|
void annotate_suspicious_entries(struct log_entry* dataset) {
|
||||||
printf("DEBUG: Prüfe %d Einträge auf verdächtige Muster...\n", total_entries);
|
printf("DEBUG: Prüfe %d Einträge auf verdächtige Muster...\n", total_entries);
|
||||||
|
|
||||||
@ -676,7 +678,7 @@ void load_log_file(char* path) {
|
|||||||
while ((entry = readdir(dir)) != NULL) {
|
while ((entry = readdir(dir)) != NULL) {
|
||||||
char* filename = (*entry).d_name;
|
char* filename = (*entry).d_name;
|
||||||
if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0) {
|
if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0) {
|
||||||
printf("WARNING: Überspringe Datei %s, unerwartete Dateisignatur", filename);
|
printf("WARNING: Überspringe Datei %s, unerwartete Dateisignatur\n", filename);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (strstr(filename, "error")!=NULL){
|
if (strstr(filename, "error")!=NULL){
|
||||||
@ -1086,49 +1088,41 @@ int passes_filter(int entry_index) {
|
|||||||
has_passing_filter = 1;
|
has_passing_filter = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.method_count > 0) {
|
if (filters.method_count > 0) {
|
||||||
if (method_matches(all_entries[entry_index].request_method)) {
|
if (method_matches(all_entries[entry_index].request_method)) {
|
||||||
has_passing_filter = 1;
|
has_passing_filter = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.ip_count > 0) {
|
if (filters.ip_count > 0) {
|
||||||
if (ip_address_matches(all_entries[entry_index].ip_address)) {
|
if (ip_address_matches(all_entries[entry_index].ip_address)) {
|
||||||
has_passing_filter = 1;
|
has_passing_filter = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.time_count > 0) {
|
if (filters.time_count > 0) {
|
||||||
if (time_matches(all_entries[entry_index].time)) {
|
if (time_matches(all_entries[entry_index].time)) {
|
||||||
has_passing_filter = 1;
|
has_passing_filter = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.user_agent_count > 0) {
|
if (filters.user_agent_count > 0) {
|
||||||
if (user_agent_matches(all_entries[entry_index].user_agent)) {
|
if (user_agent_matches(all_entries[entry_index].user_agent)) {
|
||||||
has_passing_filter = 1;
|
has_passing_filter = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.url_count > 0) {
|
if (filters.url_count > 0) {
|
||||||
if (url_matches(all_entries[entry_index].url_path)) {
|
if (url_matches(all_entries[entry_index].url_path)) {
|
||||||
has_passing_filter = 1;
|
has_passing_filter = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.annotation_flag_filter_enabled){
|
if (filters.annotation_flag_filter_enabled){
|
||||||
if (is_annotated(all_entries[entry_index].annotated_flag)) {
|
if (is_annotated(all_entries[entry_index].annotated_flag)) {
|
||||||
has_passing_filter = 1;
|
has_passing_filter = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters.annotation_count > 0){
|
if (filters.annotation_count > 0){
|
||||||
if (annotation_matches(all_entries[entry_index].annotation)){
|
if (annotation_matches(all_entries[entry_index].annotation)){
|
||||||
has_passing_filter = 1;
|
has_passing_filter = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return has_passing_filter;
|
return has_passing_filter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1179,7 +1173,6 @@ void export_filtered_entries(char *filepath) {
|
|||||||
|
|
||||||
int exported_count = 0;
|
int exported_count = 0;
|
||||||
char iso_datetime[32];
|
char iso_datetime[32];
|
||||||
char message_text[300];
|
|
||||||
|
|
||||||
for (int i = 0; i < total_entries; i++) {
|
for (int i = 0; i < total_entries; i++) {
|
||||||
if (passes_filter(i)) {
|
if (passes_filter(i)) {
|
||||||
@ -1212,6 +1205,7 @@ struct ip_stat {
|
|||||||
int count;
|
int count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// zeigt alle annotierten Einträge detailliert an
|
||||||
void show_annotated_entries() {
|
void show_annotated_entries() {
|
||||||
printf("\nLOGEINTRÄGE MIT ANNOTATION\n");
|
printf("\nLOGEINTRÄGE MIT ANNOTATION\n");
|
||||||
printf("IP-Adresse | Methode | URL | Status | Bytes | User Agent | Zeit | Annotation\n");
|
printf("IP-Adresse | Methode | URL | Status | Bytes | User Agent | Zeit | Annotation\n");
|
||||||
@ -1249,6 +1243,7 @@ void show_annotated_entries() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO doku
|
||||||
void show_top_x_ips(){
|
void show_top_x_ips(){
|
||||||
struct ip_stat ip_stats[1000];
|
struct ip_stat ip_stats[1000];
|
||||||
int unique_ips = 0;
|
int unique_ips = 0;
|
||||||
@ -1303,6 +1298,7 @@ void show_top_x_ips(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO doku
|
||||||
void show_top_user_agents(){
|
void show_top_user_agents(){
|
||||||
struct user_agent_stat {
|
struct user_agent_stat {
|
||||||
char user_agent[256];
|
char user_agent[256];
|
||||||
@ -1362,12 +1358,14 @@ void show_top_user_agents(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Zeigt jeden Eintrag, der den Filter besteht. Wird ein int !=0 übergeben, wird nur die spezifizierte Anzahl an Einträgen dargestellt.
|
||||||
|
// Verwendung in einer Komplettausgabe sowie im Preview
|
||||||
void show_filtered_entries(int num_shown) {
|
void show_filtered_entries(int num_shown) {
|
||||||
int shown_count = 0;
|
int shown_count = 0;
|
||||||
|
|
||||||
printf("\nLOGDATEN:\n");
|
printf("\nLOGDATEN:\n");
|
||||||
printf("IP-Adresse | Methode | URL | Status | Bytes | User Agent | Zeit | Annotation\n");
|
printf("IP-Adresse | Methode | URL | Status | Bytes | User Agent | Zeit | Annotation\n");
|
||||||
printf("-----------------|---------|------------------------|--------|-------|--------------------------------------|------------------|--------------------\n");
|
printf("-----------------|---------|------------------------|--------|-------|--------------------------------------|---------------------|--------------------\n");
|
||||||
|
|
||||||
for (int i = 0; i < total_entries; i++) {
|
for (int i = 0; i < total_entries; i++) {
|
||||||
if (!passes_filter(i)) continue;
|
if (!passes_filter(i)) continue;
|
||||||
@ -1403,7 +1401,7 @@ void show_filtered_entries(int num_shown) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO annotationsfilter, Zeitraumfilter
|
// Diese Funktion zeigt stets die gesetzten Filter in einem Format an, das aus dem interaktiven Modus reproduzierbar im cli-Modus wiederverwendet werden kann
|
||||||
void print_filter_args(){
|
void print_filter_args(){
|
||||||
int total_filters = filters.status_count + filters.method_count + filters.ip_count + filters.time_count + filters.user_agent_count + filters.url_count + filters.annotation_flag_filter_enabled + filters.annotation_count;
|
int total_filters = filters.status_count + filters.method_count + filters.ip_count + filters.time_count + filters.user_agent_count + filters.url_count + filters.annotation_flag_filter_enabled + filters.annotation_count;
|
||||||
|
|
||||||
@ -1416,7 +1414,7 @@ void print_filter_args(){
|
|||||||
if (filters.status_count > 0) {
|
if (filters.status_count > 0) {
|
||||||
printf("--status=");
|
printf("--status=");
|
||||||
for (int i = 0; i < filters.status_count; i++) {
|
for (int i = 0; i < filters.status_count; i++) {
|
||||||
if (i > 0) printf(",");
|
if (i > 0) {printf(",");};
|
||||||
if (filters.status_filters[i].mode == FILTER_EXCLUDE) printf("!");
|
if (filters.status_filters[i].mode == FILTER_EXCLUDE) printf("!");
|
||||||
printf("%d", filters.status_filters[i].code);
|
printf("%d", filters.status_filters[i].code);
|
||||||
}
|
}
|
||||||
@ -1426,7 +1424,7 @@ void print_filter_args(){
|
|||||||
if (filters.method_count > 0) {
|
if (filters.method_count > 0) {
|
||||||
printf("--method=");
|
printf("--method=");
|
||||||
for (int i = 0; i < filters.method_count; i++) {
|
for (int i = 0; i < filters.method_count; i++) {
|
||||||
if (i > 0) printf(",");
|
if (i > 0) {printf(",");}
|
||||||
if (filters.method_filters[i].mode == FILTER_EXCLUDE) printf("!");
|
if (filters.method_filters[i].mode == FILTER_EXCLUDE) printf("!");
|
||||||
printf("%s", filters.method_filters[i].pattern);
|
printf("%s", filters.method_filters[i].pattern);
|
||||||
}
|
}
|
||||||
@ -1436,7 +1434,7 @@ void print_filter_args(){
|
|||||||
if (filters.ip_count > 0) {
|
if (filters.ip_count > 0) {
|
||||||
printf("--ip=");
|
printf("--ip=");
|
||||||
for (int i = 0; i < filters.ip_count; i++) {
|
for (int i = 0; i < filters.ip_count; i++) {
|
||||||
if (i > 0) printf(",");
|
if (i > 0) {printf(",");};
|
||||||
if (filters.ip_filters[i].mode == FILTER_EXCLUDE) printf("!");
|
if (filters.ip_filters[i].mode == FILTER_EXCLUDE) printf("!");
|
||||||
printf("%s", filters.ip_filters[i].ip_address);
|
printf("%s", filters.ip_filters[i].ip_address);
|
||||||
}
|
}
|
||||||
@ -1446,7 +1444,7 @@ void print_filter_args(){
|
|||||||
if (filters.user_agent_count > 0) {
|
if (filters.user_agent_count > 0) {
|
||||||
printf("--useragent=");
|
printf("--useragent=");
|
||||||
for (int i = 0; i < filters.user_agent_count; i++) {
|
for (int i = 0; i < filters.user_agent_count; i++) {
|
||||||
if (i > 0) printf(",");
|
if (i > 0) {printf(",");};
|
||||||
if (filters.user_agent_filters[i].mode == FILTER_EXCLUDE) printf("!");
|
if (filters.user_agent_filters[i].mode == FILTER_EXCLUDE) printf("!");
|
||||||
printf("%s", filters.user_agent_filters[i].pattern);
|
printf("%s", filters.user_agent_filters[i].pattern);
|
||||||
}
|
}
|
||||||
@ -1456,14 +1454,34 @@ void print_filter_args(){
|
|||||||
if (filters.url_count > 0) {
|
if (filters.url_count > 0) {
|
||||||
printf("--url=");
|
printf("--url=");
|
||||||
for (int i = 0; i < filters.url_count; i++) {
|
for (int i = 0; i < filters.url_count; i++) {
|
||||||
if (i > 0) printf(",");
|
if (i > 0) {printf(",");};
|
||||||
if (filters.url_filters[i].mode == FILTER_EXCLUDE) printf("!");
|
if (filters.url_filters[i].mode == FILTER_EXCLUDE) printf("!");
|
||||||
printf("%s", filters.url_filters[i].pattern);
|
printf("%s", filters.url_filters[i].pattern);
|
||||||
}
|
}
|
||||||
printf(" ");
|
printf(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO timestamp
|
if (filters.time_count >0){
|
||||||
|
printf("--timerange=");
|
||||||
|
for(int i =0; i < filters.time_count;i++){
|
||||||
|
if(i > 0) {printf(",");};
|
||||||
|
if (filters.time_filters[i].mode == FILTER_EXCLUDE) {printf("!");};
|
||||||
|
// die führenden 0 sind hier wichtig
|
||||||
|
printf("%04d-%02d-%02d-%02d-%02d-%02d:%04d-%02d-%02d-%02d-%02d-%02d ",
|
||||||
|
filters.time_filters[i].start_time.year,
|
||||||
|
filters.time_filters[i].start_time.month,
|
||||||
|
filters.time_filters[i].start_time.day,
|
||||||
|
filters.time_filters[i].start_time.hour,
|
||||||
|
filters.time_filters[i].start_time.minute,
|
||||||
|
filters.time_filters[i].start_time.second,
|
||||||
|
filters.time_filters[i].end_time.year,
|
||||||
|
filters.time_filters[i].end_time.month,
|
||||||
|
filters.time_filters[i].end_time.day,
|
||||||
|
filters.time_filters[i].end_time.hour,
|
||||||
|
filters.time_filters[i].end_time.minute,
|
||||||
|
filters.time_filters[i].end_time.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// macht nicht viel Sinn, diese hier zu integrieren, so lang der User nicht weiß, wie die Annotationen lauten
|
// macht nicht viel Sinn, diese hier zu integrieren, so lang der User nicht weiß, wie die Annotationen lauten
|
||||||
if (filters.annotation_flag_filter_enabled) {
|
if (filters.annotation_flag_filter_enabled) {
|
||||||
@ -1490,19 +1508,18 @@ void print_filter_args(){
|
|||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
// TODO
|
|
||||||
if (filters.time_count > 0) {
|
|
||||||
printf("HINWEIS: %d Zeitraum-Filter sind aktiv, aber nur im interaktiven Modus verfügbar.\n", filters.time_count);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Status-Anzeige, die in jedem Bildschirm dynamisch eine Vorschau des gefilterten Datensatzes, sowie eine Übersicht über die gesetzten Filter anzeigt.
|
||||||
void show_status(){
|
void show_status(){
|
||||||
printf("\nPREVIEW:\n");
|
printf("\nPREVIEW:\n");
|
||||||
|
// diese Funktion wird auch an anderer Stelle mit Parameter 0 verwendet und zeigt dann alles an
|
||||||
show_filtered_entries(10);
|
show_filtered_entries(10);
|
||||||
printf("\nSTATUS\n");
|
printf("\nSTATUS\n");
|
||||||
|
|
||||||
if (total_entries > 0) {
|
if (total_entries > 0) {
|
||||||
printf(" %d Logzeilen in Datenstruktur\n", total_entries);
|
printf(" %d Logzeilen in Datenstruktur\n", total_entries);
|
||||||
|
//nicht verifiziert?
|
||||||
printf(" Speicherbelegung: %lu Bytes\n", (unsigned long)(max_entries * sizeof(struct log_entry)));
|
printf(" Speicherbelegung: %lu Bytes\n", (unsigned long)(max_entries * sizeof(struct log_entry)));
|
||||||
} else {
|
} else {
|
||||||
printf(" ERROR: Keine Einträge in Datenstruktur!\n");
|
printf(" ERROR: Keine Einträge in Datenstruktur!\n");
|
||||||
@ -1533,6 +1550,7 @@ void show_status(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TRANSPARENZ: Dies wurde KI-generiert
|
||||||
void print_filter_examples(){
|
void print_filter_examples(){
|
||||||
printf("\nFILTER-DOKUMENTATION\n");
|
printf("\nFILTER-DOKUMENTATION\n");
|
||||||
printf("\nEXKLUSIONS-FILTER (immer OR-Logik, unabhängig vom Modus):\n");
|
printf("\nEXKLUSIONS-FILTER (immer OR-Logik, unabhängig vom Modus):\n");
|
||||||
@ -1696,6 +1714,8 @@ int read_menu_input(){
|
|||||||
return (int)number;
|
return (int)number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Transparenz: Die visuelle Darstellung der Menus und dessen Formatierung, sowie repetitive schriftliche Wiedergabe wie etwa die interaktive Eingabe der Zeiträume ist teilweise KI-generiert.
|
||||||
void show_main_menu(){
|
void show_main_menu(){
|
||||||
printf("\nHAUPTMENÜ\n");
|
printf("\nHAUPTMENÜ\n");
|
||||||
printf("1. Filter verwalten\n");
|
printf("1. Filter verwalten\n");
|
||||||
@ -2293,7 +2313,7 @@ void menu_show_entries(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Funktionen zum setzen der Filter (existierende Datenstrukturen)
|
// Funktionen zum setzen der Filter (existierende Datenstrukturen)
|
||||||
void add_status_filter(char* value, filter_mode_t mode) {
|
void add_parsed_status_filter(char* value, filter_mode_t mode) {
|
||||||
if (filters.status_count >= MAX_FILTERS) {
|
if (filters.status_count >= MAX_FILTERS) {
|
||||||
printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value);
|
printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value);
|
||||||
return;
|
return;
|
||||||
@ -2317,7 +2337,7 @@ void add_status_filter(char* value, filter_mode_t mode) {
|
|||||||
printf("DEBUG: Filter hinzugefügt: %s%d\n", mode == FILTER_EXCLUDE ? "!" : "", status_code);
|
printf("DEBUG: Filter hinzugefügt: %s%d\n", mode == FILTER_EXCLUDE ? "!" : "", status_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_ip_filter(char* value, filter_mode_t mode) {
|
void add_parsed_ip_filter(char* value, filter_mode_t mode) {
|
||||||
if (filters.ip_count >= MAX_FILTERS) {
|
if (filters.ip_count >= MAX_FILTERS) {
|
||||||
printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value);
|
printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value);
|
||||||
return;
|
return;
|
||||||
@ -2338,7 +2358,7 @@ void add_ip_filter(char* value, filter_mode_t mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// gleiche Mechanik wie bei IP-Adresse
|
// gleiche Mechanik wie bei IP-Adresse
|
||||||
void add_method_filter(char* value, filter_mode_t mode) {
|
void add_parsed_method_filter(char* value, filter_mode_t mode) {
|
||||||
if (filters.method_count >= MAX_FILTERS) {
|
if (filters.method_count >= MAX_FILTERS) {
|
||||||
printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value);
|
printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value);
|
||||||
return;
|
return;
|
||||||
@ -2357,7 +2377,7 @@ void add_method_filter(char* value, filter_mode_t mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// gleiche Mechanik wie bei IP-Adresse
|
// gleiche Mechanik wie bei IP-Adresse
|
||||||
void add_useragent_filter(char* value, filter_mode_t mode) {
|
void add_parsed_useragent_filter(char* value, filter_mode_t mode) {
|
||||||
if (filters.user_agent_count >= MAX_FILTERS) {
|
if (filters.user_agent_count >= MAX_FILTERS) {
|
||||||
printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value);
|
printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value);
|
||||||
return;
|
return;
|
||||||
@ -2376,7 +2396,7 @@ void add_useragent_filter(char* value, filter_mode_t mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// gleiche Mechanik wie bei IP-Adresse
|
// gleiche Mechanik wie bei IP-Adresse
|
||||||
void add_url_filter(char* value, filter_mode_t mode) {
|
void add_parsed_url_filter(char* value, filter_mode_t mode) {
|
||||||
if (filters.url_count >= MAX_FILTERS) {
|
if (filters.url_count >= MAX_FILTERS) {
|
||||||
printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value);
|
printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value);
|
||||||
return;
|
return;
|
||||||
@ -2394,6 +2414,186 @@ void add_url_filter(char* value, filter_mode_t mode) {
|
|||||||
printf("DEBUG: URL/Payload-Filter hinzugefügt: %s%s\n", mode == FILTER_EXCLUDE ? "!" : "", value);
|
printf("DEBUG: URL/Payload-Filter hinzugefügt: %s%s\n", mode == FILTER_EXCLUDE ? "!" : "", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parsen des Timestamp-Filters ist etwas komplexer, da er in die Datenstruktur geschrieben werden muss.
|
||||||
|
void add_parsed_timerange_filter(char* value, filter_mode_t mode) {
|
||||||
|
if (filters.time_count >= MAX_FILTERS) {
|
||||||
|
printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//lokale Kopie
|
||||||
|
struct time_filter new_time_filter = {0};
|
||||||
|
//Zur Position des :, der die Startzeit von der Endzeit trennt
|
||||||
|
char* colon_pos = strchr(value, ':');
|
||||||
|
if (colon_pos == NULL) {
|
||||||
|
printf("ERROR: Missing ':' separator\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// ERsteze : durch Nullterminator. Das ist notwendig, damit strtok den Timestamp problemlos einlesen kann
|
||||||
|
*colon_pos = '\0';
|
||||||
|
//Für jeden Datenpunkt: Einlesen bis zum -, sowie Error handling, da atoi gar nix macht, wenn das Token nicht geparsed werden konnte
|
||||||
|
char* token = strtok(value, "-");
|
||||||
|
if (!token) return;
|
||||||
|
int start_year = atoi(token);
|
||||||
|
if (start_year < 1970 || start_year > 2100) {
|
||||||
|
printf("ERROR: Startjahr außerhalb des möglichen Bereichs: %d\n", start_year);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
token = strtok(NULL, "-");
|
||||||
|
if (!token) return;
|
||||||
|
int start_month = atoi(token);
|
||||||
|
if (start_month < 1 || start_month > 12) {
|
||||||
|
printf("ERROR: Startmonat außerhalb des möglichen Bereichs: %d\n", start_month);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
token = strtok(NULL, "-");
|
||||||
|
if (!token) return;
|
||||||
|
int start_day = atoi(token);
|
||||||
|
if (start_day < 1 || start_day > 31) {
|
||||||
|
printf("ERROR: Starttag außerhalb des möglichen Bereichs: %d\n", start_day);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
token = strtok(NULL, "-");
|
||||||
|
if (!token) return;
|
||||||
|
int start_hour = atoi(token);
|
||||||
|
if (start_hour < 0 || start_hour > 23) {
|
||||||
|
printf("ERROR: Startstunde außerhalb des möglichen Bereichs: %d\n", start_hour);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
token = strtok(NULL, "-");
|
||||||
|
if (!token) return;
|
||||||
|
int start_minute = atoi(token);
|
||||||
|
if (start_minute < 0 || start_minute > 59) {
|
||||||
|
printf("ERROR: Startminute außerhalb des möglichen Bereichs: %d\n", start_minute);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
token = strtok(NULL, "-");
|
||||||
|
if (!token) return;
|
||||||
|
int start_second = atoi(token);
|
||||||
|
if (start_second < 0 || start_second > 59) {
|
||||||
|
printf("ERROR: Startsekunde außerhalb des möglichen Bereichs: %d\n", start_second);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
token = strtok(colon_pos+1, "-");
|
||||||
|
if (!token) return;
|
||||||
|
int end_year = atoi(token);
|
||||||
|
if (end_year < 1970 || end_year > 2100) {
|
||||||
|
printf("ERROR: Endjahr außerhalb des möglichen Bereichs: %d\n", end_year);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
token = strtok(NULL, "-");
|
||||||
|
if (!token) return;
|
||||||
|
int end_month = atoi(token);
|
||||||
|
if (end_month < 1 || end_month > 12) {
|
||||||
|
printf("ERROR: Endmonat außerhalb des möglichen Bereichs: %d\n", end_month);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
token = strtok(NULL, "-");
|
||||||
|
if (!token) return;
|
||||||
|
int end_day = atoi(token);
|
||||||
|
if (end_day < 1 || end_day > 31) {
|
||||||
|
printf("ERROR: Endtag außerhalb des möglichen Bereichs: %d\n", end_day);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
token = strtok(NULL, "-");
|
||||||
|
if (!token) return;
|
||||||
|
int end_hour = atoi(token);
|
||||||
|
if (end_hour < 0 || end_hour > 23) {
|
||||||
|
printf("ERROR: Endstunde außerhalb des möglichen Bereichs: %d\n", end_hour);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
token = strtok(NULL, "-");
|
||||||
|
if (!token) return;
|
||||||
|
int end_minute = atoi(token);
|
||||||
|
if (end_minute < 0 || end_minute > 59) {
|
||||||
|
printf("ERROR: Endminute außerhalb des möglichen Bereichs: %d\n", end_minute);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
token = strtok(NULL, "-");
|
||||||
|
if (!token) return;
|
||||||
|
int end_second = atoi(token);
|
||||||
|
if (end_second < 0 || end_second > 59) {
|
||||||
|
printf("ERROR: Endsekunde außerhalb des möglichen Bereichs: %d\n", end_second);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// integer-Variablen in die lokale Datenstruktur schreiben
|
||||||
|
new_time_filter.start_time.year = start_year;
|
||||||
|
new_time_filter.start_time.month = start_month;
|
||||||
|
new_time_filter.start_time.day = start_day;
|
||||||
|
new_time_filter.start_time.hour = start_hour;
|
||||||
|
new_time_filter.start_time.minute = start_minute;
|
||||||
|
new_time_filter.start_time.second = start_second;
|
||||||
|
|
||||||
|
new_time_filter.end_time.year = end_year;
|
||||||
|
new_time_filter.end_time.month = end_month;
|
||||||
|
new_time_filter.end_time.day = end_day;
|
||||||
|
new_time_filter.end_time.hour = end_hour;
|
||||||
|
new_time_filter.end_time.minute = end_minute;
|
||||||
|
new_time_filter.end_time.second = end_second;
|
||||||
|
|
||||||
|
new_time_filter.mode = mode;
|
||||||
|
|
||||||
|
// Logik hier: der neue Filter wird stets an einen neuen Index geschrieben. Dieser ergibt sich aus der aktuellen ANZAHL der existierenden Zeitfilter. Das funktioniert, weil der index bei 0 beginnt
|
||||||
|
filters.time_filters[filters.time_count] = new_time_filter;
|
||||||
|
filters.time_count++;
|
||||||
|
|
||||||
|
printf("DEBUG: Zeitraum-Filter hinzugefügt (%s): %04d-%02d-%02d %02d:%02d:%02d bis %04d-%02d-%02d %02d:%02d:%02d\n",
|
||||||
|
mode == FILTER_EXCLUDE ? "ausschließen" : "einschließen",
|
||||||
|
new_time_filter.start_time.year, new_time_filter.start_time.month, new_time_filter.start_time.day,
|
||||||
|
new_time_filter.start_time.hour, new_time_filter.start_time.minute, new_time_filter.start_time.second,
|
||||||
|
new_time_filter.end_time.year, new_time_filter.end_time.month, new_time_filter.end_time.day,
|
||||||
|
new_time_filter.end_time.hour, new_time_filter.end_time.minute, new_time_filter.end_time.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
// recht einfache Mechanik für den Bool´schen Filter für annotierte Einträge
|
||||||
|
void add_parsed_annotated_filter(char* value, filter_mode_t mode) {
|
||||||
|
if (strcmp(value, "true") == 0) {
|
||||||
|
filters.annotation_flag_filter.annotation_flag_is_present = 1;
|
||||||
|
filters.annotation_flag_filter.mode = mode;
|
||||||
|
filters.annotation_flag_filter_enabled = 1;
|
||||||
|
printf("DEBUG: Annotations-Flag-Filter hinzugefügt: %s%s\n", mode == FILTER_EXCLUDE ? "!" : "", value);
|
||||||
|
// falls doch mal jemand false eingibt
|
||||||
|
} else if (strcmp(value, "false") == 0) {
|
||||||
|
filters.annotation_flag_filter.annotation_flag_is_present = 0;
|
||||||
|
filters.annotation_flag_filter.mode = mode;
|
||||||
|
filters.annotation_flag_filter_enabled = 1;
|
||||||
|
printf("DEBUG: Annotations-Flag-Filter hinzugefügt: %s%s\n", mode == FILTER_EXCLUDE ? "!" : "", value);
|
||||||
|
} else {
|
||||||
|
printf("WARNING: Ungültiger Wert für --annotated Filter: %s (nur 'true' unterstützt)\n", value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wieder gleiche Mechanik wie beim User Agent etc
|
||||||
|
void add_parsed_annotation_filter(char* value, filter_mode_t mode) {
|
||||||
|
if (filters.annotation_count >= MAX_FILTERS) {
|
||||||
|
printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(value) >= sizeof(filters.annotation_filters[0].pattern)) {
|
||||||
|
printf("WARNING: Annotations-Filterwert zu lang: %s\n", value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(filters.annotation_filters[filters.annotation_count].pattern, value);
|
||||||
|
filters.annotation_filters[filters.annotation_count].mode = mode;
|
||||||
|
filters.annotation_count++;
|
||||||
|
|
||||||
|
printf("DEBUG: Annotations-Filter hinzugefügt: %s%s\n",
|
||||||
|
mode == FILTER_EXCLUDE ? "!" : "", value);
|
||||||
|
}
|
||||||
|
|
||||||
// Funktion zum Parsen der Filter-Werte, die mit --<Filtertyp>=<Werte,Komma-getrennt> übergeben werden.
|
// Funktion zum Parsen der Filter-Werte, die mit --<Filtertyp>=<Werte,Komma-getrennt> übergeben werden.
|
||||||
// values_str sind die Werte hinter dem =, filter_type die Werte vor dem =
|
// values_str sind die Werte hinter dem =, filter_type die Werte vor dem =
|
||||||
// filter_type wird von parse_filter_argument() übergeben
|
// filter_type wird von parse_filter_argument() übergeben
|
||||||
@ -2420,15 +2620,21 @@ void parse_filter_values(char* values_str, char* filter_type) {
|
|||||||
if (strlen(token) > 0) {
|
if (strlen(token) > 0) {
|
||||||
// wenn das token Werte hat, werden die entsprechenden Funktionen aufgerufen, die die Filter setzen
|
// wenn das token Werte hat, werden die entsprechenden Funktionen aufgerufen, die die Filter setzen
|
||||||
if (strcmp(filter_type, "status") == 0) {
|
if (strcmp(filter_type, "status") == 0) {
|
||||||
add_status_filter(token, mode);
|
add_parsed_status_filter(token, mode);
|
||||||
} else if (strcmp(filter_type, "ip") == 0) {
|
} else if (strcmp(filter_type, "ip") == 0) {
|
||||||
add_ip_filter(token, mode);
|
add_parsed_ip_filter(token, mode);
|
||||||
} else if (strcmp(filter_type, "method") == 0) {
|
} else if (strcmp(filter_type, "method") == 0) {
|
||||||
add_method_filter(token, mode);
|
add_parsed_method_filter(token, mode);
|
||||||
} else if (strcmp(filter_type, "useragent") == 0) {
|
} else if (strcmp(filter_type, "useragent") == 0) {
|
||||||
add_useragent_filter(token, mode);
|
add_parsed_useragent_filter(token, mode);
|
||||||
} else if (strcmp(filter_type, "url") == 0) {
|
} else if (strcmp(filter_type, "url") == 0) {
|
||||||
add_url_filter(token, mode);
|
add_parsed_url_filter(token, mode);
|
||||||
|
} else if (strcmp(filter_type, "timerange") == 0) {
|
||||||
|
add_parsed_timerange_filter(token, mode);
|
||||||
|
} else if (strcmp(filter_type, "annotated") == 0) {
|
||||||
|
add_parsed_annotated_filter(token, mode);
|
||||||
|
} else if (strcmp(filter_type, "annotation") == 0) {
|
||||||
|
add_parsed_annotation_filter(token, mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// nächste Iteration - nächstes token einlesen, damit die while-Schleife weiteriteriert
|
// nächste Iteration - nächstes token einlesen, damit die while-Schleife weiteriteriert
|
||||||
@ -2470,6 +2676,12 @@ int parse_filter_argument(char* arg) {
|
|||||||
parse_filter_values(values, "useragent");
|
parse_filter_values(values, "useragent");
|
||||||
} else if (strstr(filter_type, "url") != NULL) {
|
} else if (strstr(filter_type, "url") != NULL) {
|
||||||
parse_filter_values(values, "url");
|
parse_filter_values(values, "url");
|
||||||
|
} else if (strstr(filter_type, "timerange") != NULL) {
|
||||||
|
parse_filter_values(values, "timerange");
|
||||||
|
} else if (strstr(filter_type, "annotated") != NULL) {
|
||||||
|
parse_filter_values(values, "annotated");
|
||||||
|
} else if (strstr(filter_type, "annotation") != NULL) {
|
||||||
|
parse_filter_values(values, "annotation");
|
||||||
} else if (strstr(filter_type, "mode") != NULL) {
|
} else if (strstr(filter_type, "mode") != NULL) {
|
||||||
if (strstr(values, "and") != NULL || strstr(values, "AND") != NULL) {
|
if (strstr(values, "and") != NULL || strstr(values, "AND") != NULL) {
|
||||||
filters.combination_mode = 0;
|
filters.combination_mode = 0;
|
||||||
|
259
src/suspicious-detection.c
Normal file
259
src/suspicious-detection.c
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2025 Mario Stöckl (mstoeck3@hs-mittweida.de).
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TRANSPARENZ
|
||||||
|
// Diese Funktion ist KI-generiert
|
||||||
|
|
||||||
|
|
||||||
|
#include "suspicious_detection.h"
|
||||||
|
|
||||||
|
// Main suspicious activity detection function
|
||||||
|
// Parameters made explicit to avoid global variable dependencies
|
||||||
|
void annotate_suspicious_entries(struct log_entry* dataset,
|
||||||
|
struct log_entry* all_entries,
|
||||||
|
int total_entries,
|
||||||
|
int* suspicious_patterns_count,
|
||||||
|
int suspicious_request_len_threshold) {
|
||||||
|
|
||||||
|
printf("DEBUG: Prüfe %d Einträge auf verdächtige Muster...\n", total_entries);
|
||||||
|
|
||||||
|
for (int i = 0; i < total_entries; i++) {
|
||||||
|
// Initialisierung der Annotation falls noch nicht gesetzt
|
||||||
|
if (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
|
||||||
|
int url_length = strlen(all_entries[i].url_path);
|
||||||
|
if (url_length > suspicious_request_len_threshold) {
|
||||||
|
annotate_entry(i, "Long Payload", all_entries);
|
||||||
|
(*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", all_entries);
|
||||||
|
(*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", all_entries);
|
||||||
|
(*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", all_entries);
|
||||||
|
(*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", all_entries);
|
||||||
|
(*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", all_entries);
|
||||||
|
(*suspicious_patterns_count)++;
|
||||||
|
is_suspicious = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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", all_entries);
|
||||||
|
(*suspicious_patterns_count)++;
|
||||||
|
is_suspicious = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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", all_entries);
|
||||||
|
(*suspicious_patterns_count)++;
|
||||||
|
is_suspicious = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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", all_entries);
|
||||||
|
(*suspicious_patterns_count)++;
|
||||||
|
is_suspicious = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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", all_entries);
|
||||||
|
(*suspicious_patterns_count)++;
|
||||||
|
is_suspicious = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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", all_entries);
|
||||||
|
(*suspicious_patterns_count)++;
|
||||||
|
is_suspicious = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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", all_entries);
|
||||||
|
(*suspicious_patterns_count)++;
|
||||||
|
is_suspicious = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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", all_entries);
|
||||||
|
(*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", all_entries);
|
||||||
|
(*suspicious_patterns_count)++;
|
||||||
|
is_suspicious = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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", all_entries);
|
||||||
|
(*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", all_entries);
|
||||||
|
(*suspicious_patterns_count)++;
|
||||||
|
is_suspicious = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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", all_entries);
|
||||||
|
(*suspicious_patterns_count)++;
|
||||||
|
is_suspicious = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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", all_entries);
|
||||||
|
(*suspicious_patterns_count)++;
|
||||||
|
is_suspicious = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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", all_entries);
|
||||||
|
(*suspicious_patterns_count)++;
|
||||||
|
is_suspicious = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("DEBUG: Analyse abgeschlossen. %d verdächtige Muster erkannt.\n", *suspicious_patterns_count);
|
||||||
|
}
|
41
src/suspicious-detection.h
Normal file
41
src/suspicious-detection.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2025 Mario Stöckl (mstoeck3@hs-mittweida.de).
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TRANSPARENZ
|
||||||
|
// Diese Funktion ist KI-generiert
|
||||||
|
|
||||||
|
#ifndef SUSPICIOUS_DETECTION_H
|
||||||
|
#define SUSPICIOUS_DETECTION_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// Forward declaration of the log_entry struct
|
||||||
|
// (The full definition should be in main.c or a shared header)
|
||||||
|
struct log_entry;
|
||||||
|
|
||||||
|
// Function declarations
|
||||||
|
void annotate_suspicious_entries(struct log_entry* dataset,
|
||||||
|
struct log_entry* all_entries,
|
||||||
|
int total_entries,
|
||||||
|
int* suspicious_patterns_count,
|
||||||
|
int suspicious_request_len_threshold);
|
||||||
|
|
||||||
|
// Helper function declarations that need to be available
|
||||||
|
void annotate_entry(int index, char* annotation_string,
|
||||||
|
struct log_entry* entries);
|
||||||
|
int search_in_string(char* raw_string, char* search_string);
|
||||||
|
|
||||||
|
#endif // SUSPICIOUS_DETECTION_H
|
Loading…
x
Reference in New Issue
Block a user