From 371945d0f157b03a3bb17b703e0edb2358f0ad67 Mon Sep 17 00:00:00 2001 From: Priyanka Chatterjee Date: Wed, 2 Apr 2025 23:21:12 +0530 Subject: [PATCH 01/62] Add initial mod --- dashboard/apache_activity_dashboard.pp | 316 +++++++++++++++++ detections/apache_access_logs.pp | 21 ++ detections/apache_compliance.pp | 206 +++++++++++ detections/apache_operational.pp | 268 ++++++++++++++ detections/apache_performance.pp | 204 +++++++++++ detections/apache_security.pp | 470 +++++++++++++++++++++++++ 6 files changed, 1485 insertions(+) create mode 100644 dashboard/apache_activity_dashboard.pp create mode 100644 detections/apache_access_logs.pp create mode 100644 detections/apache_compliance.pp create mode 100644 detections/apache_operational.pp create mode 100644 detections/apache_performance.pp create mode 100644 detections/apache_security.pp diff --git a/dashboard/apache_activity_dashboard.pp b/dashboard/apache_activity_dashboard.pp new file mode 100644 index 0000000..5fac37a --- /dev/null +++ b/dashboard/apache_activity_dashboard.pp @@ -0,0 +1,316 @@ +dashboard "apache_activity_dashboard" { + title = "Apache Log Activity Dashboard" + + tags = { + type = "Dashboard" + service = "Apache" + } + + container { + # Analysis + card { + query = query.apache_activity_dashboard_total_logs + width = 2 + } + + card { + query = query.apache_activity_dashboard_success_count + width = 2 + type = "ok" + } + + card { + query = query.apache_activity_dashboard_bad_request_count + width = 2 + type = "info" + } + + card { + query = query.apache_activity_dashboard_error_count + width = 2 + type = "alert" + } + } + + container { + chart { + title = "Top 10 Clients (Request Count)" + query = query.apache_activity_dashboard_top_10_clients + width = 6 + type = "table" + } + + chart { + title = "Top 10 URIs (Request Count)" + query = query.apache_activity_dashboard_top_10_urls + width = 6 + type = "table" + } + + chart { + title = "Status Code Distribution" + query = query.apache_activity_dashboard_status_distribution + width = 6 + type = "pie" + } + + chart { + title = "HTTP Method Distribution" + query = query.apache_activity_dashboard_method_distribution + width = 6 + type = "pie" + } + } + + container { + chart { + title = "Top 10 Slowest Endpoints" + query = query.apache_activity_dashboard_slowest_endpoints + width = 6 + type = "table" + } + + chart { + title = "Top Client Error Paths" + query = query.apache_activity_dashboard_client_error_paths + width = 6 + type = "table" + } + } + + container { + chart { + title = "Requests per Day" + query = query.apache_activity_dashboard_requests_per_day + width = 6 + type = "column" + } + + # chart { + # title = "Requests by Day of Week" + # query = query.apache_activity_dashboard_requests_by_day + # width = 6 + # type = "bar" + # } + } + + # container { + # chart { + # title = "Request Volume Over Time" + # query = query.apache_activity_dashboard_request_volume + # width = 12 + # type = "bar" + # display = "bar" + # } + # } +} + +# Queries +query "apache_activity_dashboard_total_logs" { + sql = <<-EOQ + select + count(*) as "Total Requests" + from + apache_access_log; + EOQ +} + +query "apache_activity_dashboard_success_count" { + sql = <<-EOQ + select + count(*) as "Successful (200-399)" + from + apache_access_log + where + status between 200 and 399; + EOQ +} + +query "apache_activity_dashboard_bad_request_count" { + sql = <<-EOQ + select + count(*) as "Bad Requests (400-499)" + from + apache_access_log + where + status between 400 and 499; + EOQ +} + +query "apache_activity_dashboard_error_count" { + sql = <<-EOQ + select + count(*) as "Server Errors (500-599)" + from + apache_access_log + where + status between 500 and 599; + EOQ +} + +query "apache_activity_dashboard_top_10_clients" { + sql = <<-EOQ + select + remote_addr as "Client IP", + count(*) as "Request Count" + from + apache_access_log + group by + remote_addr + order by + count(*) desc + limit 10; + EOQ +} + +query "apache_activity_dashboard_top_10_urls" { + sql = <<-EOQ + select + request_uri as "URL", + count(*) as "Request Count" + from + apache_access_log + where + request_uri is not null + group by + request_uri + order by + count(*) desc + limit 10; + EOQ +} + +query "apache_activity_dashboard_requests_per_day" { + sql = <<-EOQ + select + strftime(tp_timestamp, '%Y-%m-%d') as "Date", + count(*) as "Request Count" + from + apache_access_log + group by + strftime(tp_timestamp, '%Y-%m-%d') + order by + strftime(tp_timestamp, '%Y-%m-%d'); + EOQ +} + +query "apache_activity_dashboard_requests_by_day" { + sql = <<-EOQ + select + case extract(dow from tp_timestamp) + when 0 then 'Sunday' + when 1 then 'Monday' + when 2 then 'Tuesday' + when 3 then 'Wednesday' + when 4 then 'Thursday' + when 5 then 'Friday' + when 6 then 'Saturday' + end as "Day of Week", + count(*) as "Request Count" + from + apache_access_log + group by + extract(dow from tp_timestamp) + order by + extract(dow from tp_timestamp); + EOQ +} + +query "apache_activity_dashboard_request_volume" { + sql = <<-EOQ + select + date_trunc('day', tp_timestamp) as "Date", + count(*) as "Daily Requests" + from + apache_access_log + group by + date_trunc('day', tp_timestamp) + order by + date_trunc('day', tp_timestamp) asc; + EOQ +} + +query "apache_activity_dashboard_status_distribution" { + sql = <<-EOQ + select + case + when status between 200 and 299 then '2xx Success' + when status between 300 and 399 then '3xx Redirect' + when status between 400 and 499 then '4xx Client Error' + when status between 500 and 599 then '5xx Server Error' + else 'Other' + end as "Status Category", + count(*) as "Count" + from + apache_access_log + where + status is not null + group by + case + when status between 200 and 299 then '2xx Success' + when status between 300 and 399 then '3xx Redirect' + when status between 400 and 499 then '4xx Client Error' + when status between 500 and 599 then '5xx Server Error' + else 'Other' + end; + EOQ +} + +query "apache_activity_dashboard_method_distribution" { + sql = <<-EOQ + select + request_method as "HTTP Method", + count(*) as "Count" + from + apache_access_log + where + request_method is not null + group by + request_method + order by + count(*) desc; + EOQ +} + +query "apache_activity_dashboard_slowest_endpoints" { + sql = <<-EOQ + select + request_uri as "Endpoint", + case + when avg(request_time) < 1 then round(avg(request_time) * 1000)::text || 'ms' + else round(avg(request_time), 1)::text || 's' + end as "Avg Response Time", + count(*) as "Request Count" + from + apache_access_log + where + request_uri is not null + and request_time > 0 + group by + request_uri + having + count(*) > 5 -- Only show endpoints with more than 5 requests + order by + avg(request_time) desc + limit 10; + EOQ +} + +query "apache_activity_dashboard_client_error_paths" { + sql = <<-EOQ + select + request_uri as "Path", + count(*) as "Error Count", + string_agg(distinct status::text, ', ' order by status::text) as "Status Codes" + from + apache_access_log + where + status between 400 and 499 + and request_uri is not null + group by + request_uri + order by + count(*) desc + limit 10; + EOQ +} \ No newline at end of file diff --git a/detections/apache_access_logs.pp b/detections/apache_access_logs.pp new file mode 100644 index 0000000..a9ba99b --- /dev/null +++ b/detections/apache_access_logs.pp @@ -0,0 +1,21 @@ +benchmark "apache_access_log_detections" { + title = "Apache Access Log Detections" + description = "This benchmark contains recommendations when scanning Apache access logs." + type = "detection" + children = [ + benchmark.apache_security_detections, + benchmark.apache_operational_detections, + benchmark.apache_performance_detections, + benchmark.apache_compliance_detections + ] + + tags = merge(local.apache_access_log_detections_common_tags, { + type = "Benchmark" + }) +} + +locals { + apache_access_log_detections_common_tags = { + service = "Apache" + } +} \ No newline at end of file diff --git a/detections/apache_compliance.pp b/detections/apache_compliance.pp new file mode 100644 index 0000000..cd08df3 --- /dev/null +++ b/detections/apache_compliance.pp @@ -0,0 +1,206 @@ +locals { + apache_compliance_common_tags = merge(local.apache_access_log_detections_common_tags, { + category = "Compliance" + }) +} + +benchmark "apache_compliance_detections" { + title = "Apache Compliance Detections" + description = "This benchmark contains compliance-focused detections when scanning Apache access logs." + type = "detection" + children = [ + detection.apache_pii_data_exposure, + detection.apache_restricted_resource_access, + detection.apache_unauthorized_ip_access, + detection.apache_data_privacy_requirements + ] + + tags = merge(local.apache_compliance_common_tags, { + type = "Benchmark" + }) +} + +detection "apache_pii_data_exposure" { + title = "PII Data Exposure in URLs" + description = "Detect potential exposure of Personally Identifiable Information (PII) in URLs." + severity = "critical" + display_columns = ["request_ip", "request_path", "pii_type", "status_code", "timestamp"] + + query = query.apache_pii_data_exposure + + tags = merge(local.apache_compliance_common_tags, { + type = "Privacy" + }) +} + +query "apache_pii_data_exposure" { + sql = <<-EOQ + with pii_patterns as ( + select + request_uri as request_path, + remote_addr as request_ip, + status as status_code, + tp_timestamp as timestamp, + case + when request_uri ~ '[0-9]{3}-[0-9]{2}-[0-9]{4}' then 'SSN' + when request_uri ~ '[0-9]{16}' then 'Credit Card' + when request_uri ~ '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}' then 'Email' + when request_uri ~ '(?:password|passwd|pwd)=[^&]+' then 'Password' + when request_uri ~ '[0-9]{10}' then 'Phone Number' + end as pii_type + from + apache_access_log + where + request_uri is not null + and ( + request_uri ~ '[0-9]{3}-[0-9]{2}-[0-9]{4}' -- SSN pattern + or request_uri ~ '[0-9]{16}' -- Credit card pattern + or request_uri ~ '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}' -- Email pattern + or request_uri ~ '(?:password|passwd|pwd)=[^&]+' -- Password in URL + or request_uri ~ '[0-9]{10}' -- Phone number pattern + ) + ) + select + * + from + pii_patterns + order by + timestamp desc; + EOQ +} + +detection "apache_restricted_resource_access" { + title = "Restricted Resource Access" + description = "Detect access attempts to restricted resources or administrative areas." + severity = "high" + display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] + + query = query.apache_restricted_resource_access + + tags = merge(local.apache_compliance_common_tags, { + type = "Access" + }) +} + +query "apache_restricted_resource_access" { + sql = <<-EOQ + select + remote_addr as request_ip, + request_uri as request_path, + request_method, + status as status_code, + tp_timestamp as timestamp + from + apache_access_log + where + request_uri is not null + and ( + lower(request_uri) like '%/admin%' + or lower(request_uri) like '%/manager%' + or lower(request_uri) like '%/console%' + or lower(request_uri) like '%/dashboard%' + or lower(request_uri) like '%/management%' + or lower(request_uri) like '%/phpmyadmin%' + or lower(request_uri) like '%/wp-admin%' + or lower(request_uri) like '%/administrator%' + + -- Apache-specific sensitive paths + or lower(request_uri) like '%/server-status%' + or lower(request_uri) like '%/server-info%' + or lower(request_uri) like '%/status%' + or lower(request_uri) like '%/balancer-manager%' + ) + and status != 404 -- Exclude 404s to reduce noise + order by + timestamp desc; + EOQ +} + +detection "apache_unauthorized_ip_access" { + title = "Unauthorized IP Range Access" + description = "Detect access attempts from unauthorized IP ranges or geographic locations." + severity = "high" + display_columns = ["request_ip", "request_count", "first_access", "last_access"] + + query = query.apache_unauthorized_ip_access + + tags = merge(local.apache_compliance_common_tags, { + type = "Access" + }) +} + +query "apache_unauthorized_ip_access" { + sql = <<-EOQ + with unauthorized_access as ( + select + remote_addr as request_ip, + count(*) as request_count, + min(tp_timestamp) as first_access, + max(tp_timestamp) as last_access + from + apache_access_log + where + remote_addr not like '10.%' + and remote_addr not like '172.%' + and remote_addr not like '192.168.%' + and remote_addr not like '127.%' + group by + remote_addr + ) + select + * + from + unauthorized_access + order by + request_count desc; + EOQ +} + +detection "apache_data_privacy_requirements" { + title = "Data Privacy Requirements" + description = "Monitor compliance with data privacy requirements and sensitive data handling." + severity = "high" + display_columns = ["endpoint", "total_requests", "sensitive_data_count", "unique_ips"] + + query = query.apache_data_privacy_requirements + + tags = merge(local.apache_compliance_common_tags, { + type = "Privacy" + }) +} + +query "apache_data_privacy_requirements" { + sql = <<-EOQ + with privacy_endpoints as ( + select + request_uri as endpoint, + count(*) as total_requests, + count(*) filter ( + where request_uri ~ '(?i)(ssn|email|password|credit|card|phone|address|dob|birth)' + ) as sensitive_data_count, + count(distinct remote_addr) as unique_ips + from + apache_access_log + where + request_uri is not null + -- Focus on API endpoints and form submissions + and (request_uri like '/api/%' or request_method = 'POST') + group by + request_uri + having + count(*) filter ( + where request_uri ~ '(?i)(ssn|email|password|credit|card|phone|address|dob|birth)' + ) > 0 + ) + select + endpoint, + total_requests, + sensitive_data_count, + unique_ips, + round((sensitive_data_count::float / total_requests * 100)::numeric, 2) as sensitive_data_percentage + from + privacy_endpoints + order by + sensitive_data_count desc; + EOQ +} \ No newline at end of file diff --git a/detections/apache_operational.pp b/detections/apache_operational.pp new file mode 100644 index 0000000..33dc8f5 --- /dev/null +++ b/detections/apache_operational.pp @@ -0,0 +1,268 @@ +locals { + apache_operational_common_tags = merge(local.apache_access_log_detections_common_tags, { + category = "Operational" + }) +} + +benchmark "apache_operational_detections" { + title = "Apache Operational Detections" + description = "This benchmark contains operational detections when scanning Apache access logs." + type = "detection" + children = [ + detection.apache_high_error_rate, + detection.apache_unusual_traffic_spike, + detection.apache_error_rate_by_endpoint, + detection.apache_client_error_analysis, + detection.apache_server_error_analysis + ] + + tags = merge(local.apache_operational_common_tags, { + type = "Benchmark" + }) +} + +detection "apache_high_error_rate" { + title = "High Error Rate Detected" + description = "Detect when the rate of HTTP errors exceeds a threshold within a time window." + severity = "high" + display_columns = ["error_count", "total_requests", "error_rate", "window_start", "window_end"] + + query = query.apache_high_error_rate + + tags = merge(local.apache_operational_common_tags, { + type = "Availability" + }) +} + +query "apache_high_error_rate" { + sql = <<-EOQ + with error_windows as ( + select + count(*) filter (where status >= 400) as error_count, + count(*) as total_requests, + (count(*) filter (where status >= 400))::float / count(*) as error_rate, + time_bucket('5 minutes', tp_timestamp) as window_start, + time_bucket('5 minutes', tp_timestamp) + interval '5 minutes' as window_end + from + apache_access_log + where + status is not null + group by + time_bucket('5 minutes', tp_timestamp) + having + count(*) >= 10 -- Minimum request threshold + and (count(*) filter (where status >= 400))::float / count(*) >= 0.1 -- 10% error rate threshold + ) + select + error_count, + total_requests, + round((error_rate * 100)::numeric, 2) as error_rate, + window_start, + window_end + from + error_windows + order by + window_start desc; + EOQ +} + +detection "apache_unusual_traffic_spike" { + title = "Unusual Traffic Spike Detected" + description = "Detect unusual spikes in traffic volume compared to historical patterns." + severity = "medium" + display_columns = ["request_count", "avg_historical_requests", "deviation_percent", "window_start", "window_end"] + + query = query.apache_unusual_traffic_spike + + tags = merge(local.apache_operational_common_tags, { + type = "Anomaly" + }) +} + +query "apache_unusual_traffic_spike" { + sql = <<-EOQ + with traffic_windows as ( + select + count(*) as request_count, + time_bucket('5 minutes', tp_timestamp) as window_start, + avg(count(*)) over ( + order by time_bucket('5 minutes', tp_timestamp) + rows between 12 preceding and 1 preceding + ) as avg_historical_requests, + time_bucket('5 minutes', tp_timestamp) + interval '5 minutes' as window_end + from + apache_access_log + group by + time_bucket('5 minutes', tp_timestamp) + ) + select + request_count, + round(avg_historical_requests::numeric, 2) as avg_historical_requests, + round(((request_count - avg_historical_requests) / greatest(avg_historical_requests, 1) * 100)::numeric, 2) as deviation_percent, + window_start, + window_end + from + traffic_windows + where + avg_historical_requests > 0 + and ((request_count - avg_historical_requests) / greatest(avg_historical_requests, 1)) > 1 -- 100% increase threshold + order by + window_start desc; + EOQ +} + +detection "apache_error_rate_by_endpoint" { + title = "High Error Rate by Endpoint" + description = "Detect endpoints with unusually high error rates." + severity = "high" + display_columns = ["endpoint", "error_count", "total_requests", "error_rate"] + + query = query.apache_error_rate_by_endpoint + + tags = merge(local.apache_operational_common_tags, { + type = "Availability" + }) +} + +query "apache_error_rate_by_endpoint" { + sql = <<-EOQ + select + request_uri as endpoint, + count(*) filter (where status >= 400) as error_count, + count(*) as total_requests, + round((count(*) filter (where status >= 400))::float / count(*)::numeric, 4) * 100 as error_rate + from + apache_access_log + where + request_uri is not null + and status is not null + group by + request_uri + having + count(*) >= 5 -- Minimum request threshold + and (count(*) filter (where status >= 400))::float / count(*) >= 0.1 -- 10% error rate threshold + order by + error_rate desc, + total_requests desc; + EOQ +} + +detection "apache_client_error_analysis" { + title = "Client Error Analysis" + description = "Analyze patterns in client-side errors (4xx) to identify potential client issues." + severity = "medium" + display_columns = ["status_code", "error_count", "percentage", "top_uri", "uri_count"] + + query = query.apache_client_error_analysis + + tags = merge(local.apache_operational_common_tags, { + type = "Availability" + }) +} + +query "apache_client_error_analysis" { + sql = <<-EOQ + with client_errors as ( + select + status as status_code, + count(*) as error_count + from + apache_access_log + where + status >= 400 and status < 500 + group by + status + ), + error_uris as ( + select + status as status_code, + request_uri, + count(*) as uri_count, + row_number() over (partition by status order by count(*) desc) as rn + from + apache_access_log + where + status >= 400 and status < 500 + and request_uri is not null + group by + status, request_uri + ), + total_client_errors as ( + select sum(error_count) as total from client_errors + ) + select + ce.status_code, + ce.error_count, + round((ce.error_count * 100.0 / tce.total)::numeric, 2) as percentage, + eu.request_uri as top_uri, + eu.uri_count + from + client_errors ce + join + total_client_errors tce on true + left join + error_uris eu on ce.status_code = eu.status_code and eu.rn = 1 + order by + ce.error_count desc; + EOQ +} + +detection "apache_server_error_analysis" { + title = "Server Error Analysis" + description = "Analyze patterns in server-side errors (5xx) to identify potential server issues." + severity = "high" + display_columns = ["status_code", "error_count", "percentage", "top_uri", "uri_count"] + + query = query.apache_server_error_analysis + + tags = merge(local.apache_operational_common_tags, { + type = "Availability" + }) +} + +query "apache_server_error_analysis" { + sql = <<-EOQ + with server_errors as ( + select + status as status_code, + count(*) as error_count + from + apache_access_log + where + status >= 500 + group by + status + ), + error_uris as ( + select + status as status_code, + request_uri, + count(*) as uri_count, + row_number() over (partition by status order by count(*) desc) as rn + from + apache_access_log + where + status >= 500 + and request_uri is not null + group by + status, request_uri + ), + total_server_errors as ( + select sum(error_count) as total from server_errors + ) + select + se.status_code, + se.error_count, + round((se.error_count * 100.0 / tse.total)::numeric, 2) as percentage, + eu.request_uri as top_uri, + eu.uri_count + from + server_errors se + join + total_server_errors tse on true + left join + error_uris eu on se.status_code = eu.status_code and eu.rn = 1 + order by + se.error_count desc; + EOQ +} \ No newline at end of file diff --git a/detections/apache_performance.pp b/detections/apache_performance.pp new file mode 100644 index 0000000..924523d --- /dev/null +++ b/detections/apache_performance.pp @@ -0,0 +1,204 @@ +locals { + apache_performance_common_tags = merge(local.apache_access_log_detections_common_tags, { + category = "Performance" + }) +} + +benchmark "apache_performance_detections" { + title = "Apache Performance Detections" + description = "This benchmark contains performance-focused detections when scanning Apache access logs." + type = "detection" + children = [ + detection.apache_slow_response_time, + detection.apache_response_time_anomalies, + detection.apache_high_traffic_endpoints, + detection.apache_connection_pool_exhaustion + ] + + tags = merge(local.apache_performance_common_tags, { + type = "Benchmark" + }) +} + +detection "apache_slow_response_time" { + title = "Slow Response Time Detected" + description = "Detect endpoints with consistently high response times exceeding threshold." + severity = "high" + display_columns = ["endpoint", "avg_response_time", "request_count", "max_response_time"] + + query = query.apache_slow_response_time + + tags = merge(local.apache_performance_common_tags, { + type = "Latency" + }) +} + +query "apache_slow_response_time" { + sql = <<-EOQ + with response_stats as ( + select + request_uri as endpoint, + count(*) as request_count, + avg(request_time) as avg_response_time, + max(request_time) as max_response_time + from + apache_access_log + where + request_uri is not null + and request_time > 0 + group by + request_uri + having + count(*) >= 5 -- Minimum request threshold + ) + select + endpoint, + round(avg_response_time::numeric, 3) as avg_response_time, + request_count, + round(max_response_time::numeric, 3) as max_response_time + from + response_stats + where + avg_response_time > 1 -- 1 second threshold + or max_response_time > 3 -- 3 second max threshold + order by + avg_response_time desc; + EOQ +} + +detection "apache_response_time_anomalies" { + title = "Response Time Anomalies Detected" + description = "Detect sudden increases in response time compared to historical patterns." + severity = "high" + display_columns = ["window_start", "window_end", "avg_response_time", "historical_avg", "deviation_percent"] + + query = query.apache_response_time_anomalies + + tags = merge(local.apache_performance_common_tags, { + type = "Anomaly" + }) +} + +query "apache_response_time_anomalies" { + sql = <<-EOQ + with time_windows as ( + select + time_bucket('5 minutes', tp_timestamp) as window_start, + time_bucket('5 minutes', tp_timestamp) + interval '5 minutes' as window_end, + avg(request_time) as avg_response_time, + avg(avg(request_time)) over ( + order by time_bucket('5 minutes', tp_timestamp) + rows between 12 preceding and 1 preceding + ) as historical_avg + from + apache_access_log + where + request_time > 0 + group by + time_bucket('5 minutes', tp_timestamp) + ) + select + window_start, + window_end, + round(avg_response_time::numeric, 3) as avg_response_time, + round(historical_avg::numeric, 3) as historical_avg, + round(((avg_response_time - historical_avg) / greatest(historical_avg, 0.001) * 100)::numeric, 2) as deviation_percent + from + time_windows + where + historical_avg > 0 + and ((avg_response_time - historical_avg) / greatest(historical_avg, 0.001)) > 0.5 -- 50% increase threshold + order by + window_start desc; + EOQ +} + +detection "apache_high_traffic_endpoints" { + title = "High Traffic Endpoints" + description = "Identify endpoints receiving unusually high traffic volumes." + severity = "medium" + display_columns = ["endpoint", "request_count", "traffic_percent", "avg_response_time"] + + query = query.apache_high_traffic_endpoints + + tags = merge(local.apache_performance_common_tags, { + type = "Capacity" + }) +} + +query "apache_high_traffic_endpoints" { + sql = <<-EOQ + with endpoint_traffic as ( + select + request_uri as endpoint, + count(*) as request_count, + avg(request_time) as avg_response_time, + sum(bytes_sent) as total_bytes_sent + from + apache_access_log + where + request_uri is not null + group by + request_uri + ), + total_requests as ( + select sum(request_count) as total + from endpoint_traffic + ) + select + endpoint, + request_count, + round((request_count * 100.0 / tr.total)::numeric, 2) as traffic_percent, + round(avg_response_time::numeric, 3) as avg_response_time + from + endpoint_traffic et + cross join + total_requests tr + where + request_count > 10 -- Minimum request threshold + order by + request_count desc + limit 10; + EOQ +} + +detection "apache_connection_pool_exhaustion" { + title = "Connection Pool Exhaustion Risk" + description = "Detect risk of connection pool exhaustion based on concurrent connections." + severity = "critical" + display_columns = ["timestamp", "concurrent_connections", "rejection_rate"] + + query = query.apache_connection_pool_exhaustion + + tags = merge(local.apache_performance_common_tags, { + type = "Capacity" + }) +} + +query "apache_connection_pool_exhaustion" { + sql = <<-EOQ + with connection_stats as ( + select + time_bucket('1 minute', tp_timestamp) as timestamp, + count(*) as concurrent_connections, + count(*) filter (where status = 503) / nullif(count(*), 0)::float * 100 as rejection_rate + from + apache_access_log + where + status is not null + group by + time_bucket('1 minute', tp_timestamp) + ) + select + timestamp, + concurrent_connections, + round(rejection_rate::numeric, 2) as rejection_rate + from + connection_stats + where + concurrent_connections > 100 -- Adjust based on server capacity + or rejection_rate > 5 -- 5% rejection rate threshold + order by + timestamp desc; + EOQ +} \ No newline at end of file diff --git a/detections/apache_security.pp b/detections/apache_security.pp new file mode 100644 index 0000000..8947955 --- /dev/null +++ b/detections/apache_security.pp @@ -0,0 +1,470 @@ +locals { + apache_security_common_tags = merge(local.apache_access_log_detections_common_tags, { + category = "Security" + }) +} + +benchmark "apache_security_detections" { + title = "Apache Security Detections" + description = "This benchmark contains security-focused detections when scanning Apache access logs." + type = "detection" + children = [ + detection.apache_sql_injection_attempts, + detection.apache_directory_traversal_attempts, + detection.apache_brute_force_auth_attempts, + detection.apache_suspicious_user_agents, + detection.apache_xss_attempts, + detection.apache_sensitive_file_access, + detection.apache_unusual_http_methods, + detection.apache_web_shell_detection, + # detection.apache_log4j_exploitation_attempts, + detection.apache_api_key_exposure + ] + + tags = merge(local.apache_security_common_tags, { + type = "Benchmark" + }) +} + +detection "apache_sql_injection_attempts" { + title = "SQL Injection Attempts Detected" + description = "Detect potential SQL injection attempts in URL parameters and request paths." + severity = "critical" + display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] + + query = query.apache_sql_injection_attempts + + tags = merge(local.apache_security_common_tags, { + mitre_attack_ids = "TA0009:T1190" + }) +} + +query "apache_sql_injection_attempts" { + sql = <<-EOQ + select + remote_addr as request_ip, + request_uri as request_path, + request_method, + status as status_code, + tp_timestamp as timestamp + from + apache_access_log + where + request_uri is not null + and ( + lower(request_uri) like '%select%from%' + or lower(request_uri) like '%union%select%' + or lower(request_uri) like '%insert%into%' + or lower(request_uri) like '%delete%from%' + or lower(request_uri) like '%update%set%' + or lower(request_uri) like '%drop%table%' + or lower(request_uri) like '%or%1=1%' + or lower(request_uri) like '%or%1%=%1%' + ) + order by + tp_timestamp desc; + EOQ +} + +detection "apache_directory_traversal_attempts" { + title = "Directory Traversal Attempts Detected" + description = "Detect attempts to traverse directories using ../ patterns in URLs." + severity = "high" + display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] + + query = query.apache_directory_traversal_attempts + + tags = merge(local.apache_security_common_tags, { + mitre_attack_ids = "TA0009:T1083" + }) +} + +query "apache_directory_traversal_attempts" { + sql = <<-EOQ + select + remote_addr as request_ip, + request_uri as request_path, + request_method, + status as status_code, + tp_timestamp as timestamp + from + apache_access_log + where + request_uri is not null + and ( + -- Plain directory traversal attempts + request_uri like '%../%' + or request_uri like '%/../%' + or request_uri like '%/./%' + -- URL-encoded variants (both cases) + or request_uri like '%..%2f%' + or request_uri like '%..%2F%' + or request_uri like '%%%2e%%2e%%2f%' + or request_uri like '%%%2E%%2E%%2F%' + ) + order by + tp_timestamp desc; + EOQ +} + +detection "apache_brute_force_auth_attempts" { + title = "Authentication Brute Force Attempts" + description = "Detect potential brute force authentication attempts based on high frequency of 401/403 errors from the same IP." + severity = "high" + display_columns = ["request_ip", "target_path", "failed_attempts", "first_attempt", "last_attempt"] + + query = query.apache_brute_force_auth_attempts + + tags = merge(local.apache_security_common_tags, { + mitre_attack_ids = "TA0006:T1110" + }) +} + +query "apache_brute_force_auth_attempts" { + sql = <<-EOQ + with failed_auths as ( + select + remote_addr as request_ip, + request_uri as target_path, + count(*) as failed_attempts, + min(tp_timestamp) as first_attempt, + max(tp_timestamp) as last_attempt + from + apache_access_log + where + status in (401, 403) + and request_uri is not null + group by + remote_addr, request_uri + having + count(*) >= 5 + and (max(tp_timestamp) - min(tp_timestamp)) <= interval '5 minutes' + ) + select + * + from + failed_auths + order by + failed_attempts desc; + EOQ +} + +detection "apache_suspicious_user_agents" { + title = "Suspicious User Agents Detected" + description = "Detect requests from known malicious or suspicious user agents." + severity = "medium" + display_columns = ["request_ip", "user_agent", "request_path", "status_code", "timestamp"] + + query = query.apache_suspicious_user_agents + + tags = merge(local.apache_security_common_tags, { + mitre_attack_ids = "TA0043:T1592" + }) +} + +query "apache_suspicious_user_agents" { + sql = <<-EOQ + select + remote_addr as request_ip, + http_user_agent as user_agent, + request_uri as request_path, + status as status_code, + tp_timestamp as timestamp + from + apache_access_log + where + http_user_agent is not null + and ( + lower(http_user_agent) like '%sqlmap%' + or lower(http_user_agent) like '%nikto%' + or lower(http_user_agent) like '%nmap%' + or lower(http_user_agent) like '%masscan%' + or lower(http_user_agent) like '%gobuster%' + or lower(http_user_agent) like '%dirbuster%' + or lower(http_user_agent) like '%hydra%' + or lower(http_user_agent) like '%burpsuite%' + or lower(http_user_agent) like '%nessus%' + or lower(http_user_agent) like '%metasploit%' + or http_user_agent is null + ) + order by + tp_timestamp desc; + EOQ +} + +detection "apache_xss_attempts" { + title = "Cross-Site Scripting (XSS) Attempts" + description = "Detect potential XSS attacks in request parameters and paths." + severity = "critical" + display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] + + query = query.apache_xss_attempts + + tags = merge(local.apache_security_common_tags, { + mitre_attack_ids = "TA0009:T1059.007" + }) +} + +query "apache_xss_attempts" { + sql = <<-EOQ + select + remote_addr as request_ip, + request_uri as request_path, + request_method, + status as status_code, + tp_timestamp as timestamp + from + apache_access_log + where + request_uri is not null + and ( + -- Plain XSS patterns + lower(request_uri) like '% Date: Thu, 3 Apr 2025 17:19:07 +0530 Subject: [PATCH 02/62] Update Apache Activity Dashboard: Revise chart titles and queries for improved data visualization; remove unused queries and streamline dashboard layout. --- .../apache_activity_dashboard.pp | 229 +++++++++++------- dashboards/docs/apache_activity_dashboard.md | 11 + detections/apache_access_logs.pp | 6 - 3 files changed, 151 insertions(+), 95 deletions(-) rename {dashboard => dashboards}/apache_activity_dashboard.pp (56%) create mode 100644 dashboards/docs/apache_activity_dashboard.md diff --git a/dashboard/apache_activity_dashboard.pp b/dashboards/apache_activity_dashboard.pp similarity index 56% rename from dashboard/apache_activity_dashboard.pp rename to dashboards/apache_activity_dashboard.pp index 5fac37a..129c0cf 100644 --- a/dashboard/apache_activity_dashboard.pp +++ b/dashboards/apache_activity_dashboard.pp @@ -1,5 +1,6 @@ dashboard "apache_activity_dashboard" { - title = "Apache Log Activity Dashboard" + title = "Apache Log Activity Dashboard" + documentation = file("./dashboards/docs/apache_activity_dashboard.md") tags = { type = "Dashboard" @@ -9,113 +10,111 @@ container { # Analysis card { - query = query.apache_activity_dashboard_total_logs + query = query.activity_dashboard_total_logs width = 2 } card { - query = query.apache_activity_dashboard_success_count + query = query.activity_dashboard_success_count width = 2 type = "ok" } card { - query = query.apache_activity_dashboard_bad_request_count + query = query.activity_dashboard_bad_request_count width = 2 type = "info" } card { - query = query.apache_activity_dashboard_error_count + query = query.activity_dashboard_error_count width = 2 type = "alert" } } container { + chart { - title = "Top 10 Clients (Request Count)" - query = query.apache_activity_dashboard_top_10_clients + title = "Status Code Distribution" + query = query.activity_dashboard_status_distribution width = 6 - type = "table" + type = "pie" } chart { - title = "Top 10 URIs (Request Count)" - query = query.apache_activity_dashboard_top_10_urls + title = "HTTP Method Distribution" + query = query.activity_dashboard_method_distribution width = 6 - type = "table" + type = "column" } chart { - title = "Status Code Distribution" - query = query.apache_activity_dashboard_status_distribution + title = "Requests per Day" + query = query.activity_dashboard_requests_per_day width = 6 - type = "pie" + type = "line" } chart { - title = "HTTP Method Distribution" - query = query.apache_activity_dashboard_method_distribution + title = "User Agents Distribution" + query = query.activity_dashboard_user_agents_distribution width = 6 type = "pie" } - } - container { chart { - title = "Top 10 Slowest Endpoints" - query = query.apache_activity_dashboard_slowest_endpoints + title = "Top 10 Clients (Request Count)" + query = query.activity_dashboard_top_10_clients width = 6 type = "table" } chart { - title = "Top Client Error Paths" - query = query.apache_activity_dashboard_client_error_paths + title = "Top 10 URIs (Request Count)" + query = query.activity_dashboard_top_10_urls width = 6 type = "table" } - } - container { chart { - title = "Requests per Day" - query = query.apache_activity_dashboard_requests_per_day + title = "Top 10 Slowest Endpoints" + query = query.activity_dashboard_slowest_endpoints width = 6 - type = "column" + type = "table" } - # chart { - # title = "Requests by Day of Week" - # query = query.apache_activity_dashboard_requests_by_day - # width = 6 - # type = "bar" - # } + chart { + title = "Top Client Error Paths" + query = query.activity_dashboard_client_error_paths + width = 6 + type = "table" + } } - # container { - # chart { - # title = "Request Volume Over Time" - # query = query.apache_activity_dashboard_request_volume - # width = 12 - # type = "bar" - # display = "bar" - # } - # } } # Queries -query "apache_activity_dashboard_total_logs" { +query "activity_dashboard_total_logs" { + title = "Log Count" + description = "Count the total Apache log entries." + sql = <<-EOQ select count(*) as "Total Requests" from apache_access_log; EOQ + + tags = { + folder = "Apache" + } } -query "apache_activity_dashboard_success_count" { +query "activity_dashboard_success_count" { + title = "Successful Request Count" + description = "Count of successful HTTP requests (status 200-399)." + sql = <<-EOQ select count(*) as "Successful (200-399)" @@ -124,9 +123,16 @@ where status between 200 and 399; EOQ + + tags = { + folder = "Apache" + } } -query "apache_activity_dashboard_bad_request_count" { +query "activity_dashboard_bad_request_count" { + title = "Bad Request Count" + description = "Count of client error HTTP requests (status 400-499)." + sql = <<-EOQ select count(*) as "Bad Requests (400-499)" @@ -135,9 +141,16 @@ where status between 400 and 499; EOQ + + tags = { + folder = "Apache" + } } -query "apache_activity_dashboard_error_count" { +query "activity_dashboard_error_count" { + title = "Server Error Count" + description = "Count of server error HTTP requests (status 500-599)." + sql = <<-EOQ select count(*) as "Server Errors (500-599)" @@ -146,9 +159,16 @@ where status between 500 and 599; EOQ + + tags = { + folder = "Apache" + } } -query "apache_activity_dashboard_top_10_clients" { +query "activity_dashboard_top_10_clients" { + title = "Top 10 Clients" + description = "List the top 10 client IPs by request count." + sql = <<-EOQ select remote_addr as "Client IP", @@ -161,9 +181,16 @@ count(*) desc limit 10; EOQ + + tags = { + folder = "Apache" + } } -query "apache_activity_dashboard_top_10_urls" { +query "activity_dashboard_top_10_urls" { + title = "Top 10 URIs" + description = "List the top 10 requested URIs by request count." + sql = <<-EOQ select request_uri as "URL", @@ -178,9 +205,16 @@ count(*) desc limit 10; EOQ + + tags = { + folder = "Apache" + } } -query "apache_activity_dashboard_requests_per_day" { +query "activity_dashboard_requests_per_day" { + title = "Requests per Day" + description = "Count of requests grouped by day." + sql = <<-EOQ select strftime(tp_timestamp, '%Y-%m-%d') as "Date", @@ -192,45 +226,16 @@ order by strftime(tp_timestamp, '%Y-%m-%d'); EOQ -} -query "apache_activity_dashboard_requests_by_day" { - sql = <<-EOQ - select - case extract(dow from tp_timestamp) - when 0 then 'Sunday' - when 1 then 'Monday' - when 2 then 'Tuesday' - when 3 then 'Wednesday' - when 4 then 'Thursday' - when 5 then 'Friday' - when 6 then 'Saturday' - end as "Day of Week", - count(*) as "Request Count" - from - apache_access_log - group by - extract(dow from tp_timestamp) - order by - extract(dow from tp_timestamp); - EOQ + tags = { + folder = "Apache" + } } -query "apache_activity_dashboard_request_volume" { - sql = <<-EOQ - select - date_trunc('day', tp_timestamp) as "Date", - count(*) as "Daily Requests" - from - apache_access_log - group by - date_trunc('day', tp_timestamp) - order by - date_trunc('day', tp_timestamp) asc; - EOQ -} +query "activity_dashboard_status_distribution" { + title = "Status Code Distribution" + description = "Distribution of HTTP status codes by category." -query "apache_activity_dashboard_status_distribution" { sql = <<-EOQ select case @@ -240,7 +245,7 @@ when status between 500 and 599 then '5xx Server Error' else 'Other' end as "Status Category", - count(*) as "Count" + count(*) as "Request Count" from apache_access_log where @@ -254,13 +259,20 @@ else 'Other' end; EOQ + + tags = { + folder = "Apache" + } } -query "apache_activity_dashboard_method_distribution" { +query "activity_dashboard_method_distribution" { + title = "HTTP Method Distribution" + description = "Distribution of HTTP methods used in requests." + sql = <<-EOQ select request_method as "HTTP Method", - count(*) as "Count" + count(*) as "Request Count" from apache_access_log where @@ -270,9 +282,16 @@ order by count(*) desc; EOQ + + tags = { + folder = "Apache" + } } -query "apache_activity_dashboard_slowest_endpoints" { +query "activity_dashboard_slowest_endpoints" { + title = "Top 10 Slowest Endpoints" + description = "List of the 10 slowest endpoints by average response time." + sql = <<-EOQ select request_uri as "Endpoint", @@ -294,9 +313,16 @@ avg(request_time) desc limit 10; EOQ + + tags = { + folder = "Apache" + } } -query "apache_activity_dashboard_client_error_paths" { +query "activity_dashboard_client_error_paths" { + title = "Top Client Error Paths" + description = "List of paths that generated the most client errors (status 400-499)." + sql = <<-EOQ select request_uri as "Path", @@ -313,4 +339,29 @@ count(*) desc limit 10; EOQ + + tags = { + folder = "Apache" + } +} + +query "activity_dashboard_user_agents_distribution" { + title = "User Agents Distribution" + description = "Distribution of user agents in requests." + + sql = <<-EOQ + select + http_user_agent as "User Agent", + count(*) as "Request Count" + from + apache_access_log + where + http_user_agent is not null + group by + http_user_agent; + EOQ + + tags = { + folder = "Apache" + } } \ No newline at end of file diff --git a/dashboards/docs/apache_activity_dashboard.md b/dashboards/docs/apache_activity_dashboard.md new file mode 100644 index 0000000..44e86be --- /dev/null +++ b/dashboards/docs/apache_activity_dashboard.md @@ -0,0 +1,11 @@ +This dashboard answers the following questions: + +- How many HTTP requests has the Apache server handled? +- What is the distribution of HTTP status codes (success, redirect, client errors, server errors)? +- What HTTP methods are being used most frequently? +- How has request volume changed over time? +- Which browsers and tools are accessing the server? +- Which client IPs are generating the most traffic? +- Which URIs are most frequently requested? +- Which endpoints have the slowest response times? +- Which paths are generating the most client errors? diff --git a/detections/apache_access_logs.pp b/detections/apache_access_logs.pp index a9ba99b..e09de08 100644 --- a/detections/apache_access_logs.pp +++ b/detections/apache_access_logs.pp @@ -13,9 +13,3 @@ type = "Benchmark" }) } - -locals { - apache_access_log_detections_common_tags = { - service = "Apache" - } -} \ No newline at end of file From 60c41ba05462451f70b19ce5d9eccdeece685e2f Mon Sep 17 00:00:00 2001 From: Priyanka Chatterjee Date: Thu, 3 Apr 2025 18:33:31 +0530 Subject: [PATCH 03/62] Refactor Apache Detection Modules: Remove deprecated detections, update queries and tags for compliance, and introduce new detection methods for performance and security monitoring. --- detections/apache_compliance.pp | 97 +----------- detections/apache_operational.pp | 259 +++++++------------------------ detections/apache_performance.pp | 220 +++++++++----------------- detections/apache_security.pp | 89 ----------- mitre_attack_v161/docs/mitre.md | 5 + mitre_attack_v161/mitre.pp | 19 +++ 6 files changed, 155 insertions(+), 534 deletions(-) create mode 100644 mitre_attack_v161/docs/mitre.md create mode 100644 mitre_attack_v161/mitre.pp diff --git a/detections/apache_compliance.pp b/detections/apache_compliance.pp index cd08df3..5cd93a4 100644 --- a/detections/apache_compliance.pp +++ b/detections/apache_compliance.pp @@ -10,9 +10,7 @@ type = "detection" children = [ detection.apache_pii_data_exposure, - detection.apache_restricted_resource_access, - detection.apache_unauthorized_ip_access, - detection.apache_data_privacy_requirements + detection.apache_restricted_resource_access ] tags = merge(local.apache_compliance_common_tags, { @@ -29,7 +27,7 @@ query = query.apache_pii_data_exposure tags = merge(local.apache_compliance_common_tags, { - type = "Privacy" + mitre_attack_id = "TA0006:T1552.001" # Credential Access:Credentials In Files }) } @@ -78,7 +76,7 @@ query = query.apache_restricted_resource_access tags = merge(local.apache_compliance_common_tags, { - type = "Access" + mitre_attack_id = "TA0001:T1190,TA0008:T1133" # Initial Access:Exploit Public-Facing Application, Lateral Movement:External Remote Services }) } @@ -114,93 +112,4 @@ order by timestamp desc; EOQ -} - -detection "apache_unauthorized_ip_access" { - title = "Unauthorized IP Range Access" - description = "Detect access attempts from unauthorized IP ranges or geographic locations." - severity = "high" - display_columns = ["request_ip", "request_count", "first_access", "last_access"] - - query = query.apache_unauthorized_ip_access - - tags = merge(local.apache_compliance_common_tags, { - type = "Access" - }) -} - -query "apache_unauthorized_ip_access" { - sql = <<-EOQ - with unauthorized_access as ( - select - remote_addr as request_ip, - count(*) as request_count, - min(tp_timestamp) as first_access, - max(tp_timestamp) as last_access - from - apache_access_log - where - remote_addr not like '10.%' - and remote_addr not like '172.%' - and remote_addr not like '192.168.%' - and remote_addr not like '127.%' - group by - remote_addr - ) - select - * - from - unauthorized_access - order by - request_count desc; - EOQ -} - -detection "apache_data_privacy_requirements" { - title = "Data Privacy Requirements" - description = "Monitor compliance with data privacy requirements and sensitive data handling." - severity = "high" - display_columns = ["endpoint", "total_requests", "sensitive_data_count", "unique_ips"] - - query = query.apache_data_privacy_requirements - - tags = merge(local.apache_compliance_common_tags, { - type = "Privacy" - }) -} - -query "apache_data_privacy_requirements" { - sql = <<-EOQ - with privacy_endpoints as ( - select - request_uri as endpoint, - count(*) as total_requests, - count(*) filter ( - where request_uri ~ '(?i)(ssn|email|password|credit|card|phone|address|dob|birth)' - ) as sensitive_data_count, - count(distinct remote_addr) as unique_ips - from - apache_access_log - where - request_uri is not null - -- Focus on API endpoints and form submissions - and (request_uri like '/api/%' or request_method = 'POST') - group by - request_uri - having - count(*) filter ( - where request_uri ~ '(?i)(ssn|email|password|credit|card|phone|address|dob|birth)' - ) > 0 - ) - select - endpoint, - total_requests, - sensitive_data_count, - unique_ips, - round((sensitive_data_count::float / total_requests * 100)::numeric, 2) as sensitive_data_percentage - from - privacy_endpoints - order by - sensitive_data_count desc; - EOQ } \ No newline at end of file diff --git a/detections/apache_operational.pp b/detections/apache_operational.pp index 33dc8f5..987f803 100644 --- a/detections/apache_operational.pp +++ b/detections/apache_operational.pp @@ -9,11 +9,9 @@ description = "This benchmark contains operational detections when scanning Apache access logs." type = "detection" children = [ - detection.apache_high_error_rate, - detection.apache_unusual_traffic_spike, - detection.apache_error_rate_by_endpoint, - detection.apache_client_error_analysis, - detection.apache_server_error_analysis + detection.apache_status_500_errors, + detection.apache_missing_user_agent, + detection.apache_large_payload_requests ] tags = merge(local.apache_operational_common_tags, { @@ -21,248 +19,95 @@ }) } -detection "apache_high_error_rate" { - title = "High Error Rate Detected" - description = "Detect when the rate of HTTP errors exceeds a threshold within a time window." +detection "apache_status_500_errors" { + title = "HTTP 500 Internal Server Errors" + description = "Detect individual HTTP 500 Internal Server Error responses that indicate server-side failures." severity = "high" - display_columns = ["error_count", "total_requests", "error_rate", "window_start", "window_end"] + display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] - query = query.apache_high_error_rate + query = query.apache_status_500_errors tags = merge(local.apache_operational_common_tags, { - type = "Availability" + mitre_attack_id = "TA0040:T1499.004" # Impact:Application or System Exploitation }) } -query "apache_high_error_rate" { +query "apache_status_500_errors" { sql = <<-EOQ - with error_windows as ( - select - count(*) filter (where status >= 400) as error_count, - count(*) as total_requests, - (count(*) filter (where status >= 400))::float / count(*) as error_rate, - time_bucket('5 minutes', tp_timestamp) as window_start, - time_bucket('5 minutes', tp_timestamp) + interval '5 minutes' as window_end - from - apache_access_log - where - status is not null - group by - time_bucket('5 minutes', tp_timestamp) - having - count(*) >= 10 -- Minimum request threshold - and (count(*) filter (where status >= 400))::float / count(*) >= 0.1 -- 10% error rate threshold - ) select - error_count, - total_requests, - round((error_rate * 100)::numeric, 2) as error_rate, - window_start, - window_end + remote_addr as request_ip, + request_uri as request_path, + request_method, + status as status_code, + tp_timestamp as timestamp from - error_windows - order by - window_start desc; - EOQ -} - -detection "apache_unusual_traffic_spike" { - title = "Unusual Traffic Spike Detected" - description = "Detect unusual spikes in traffic volume compared to historical patterns." - severity = "medium" - display_columns = ["request_count", "avg_historical_requests", "deviation_percent", "window_start", "window_end"] - - query = query.apache_unusual_traffic_spike - - tags = merge(local.apache_operational_common_tags, { - type = "Anomaly" - }) -} - -query "apache_unusual_traffic_spike" { - sql = <<-EOQ - with traffic_windows as ( - select - count(*) as request_count, - time_bucket('5 minutes', tp_timestamp) as window_start, - avg(count(*)) over ( - order by time_bucket('5 minutes', tp_timestamp) - rows between 12 preceding and 1 preceding - ) as avg_historical_requests, - time_bucket('5 minutes', tp_timestamp) + interval '5 minutes' as window_end - from - apache_access_log - group by - time_bucket('5 minutes', tp_timestamp) - ) - select - request_count, - round(avg_historical_requests::numeric, 2) as avg_historical_requests, - round(((request_count - avg_historical_requests) / greatest(avg_historical_requests, 1) * 100)::numeric, 2) as deviation_percent, - window_start, - window_end - from - traffic_windows + apache_access_log where - avg_historical_requests > 0 - and ((request_count - avg_historical_requests) / greatest(avg_historical_requests, 1)) > 1 -- 100% increase threshold + status = 500 order by - window_start desc; + tp_timestamp desc; EOQ } -detection "apache_error_rate_by_endpoint" { - title = "High Error Rate by Endpoint" - description = "Detect endpoints with unusually high error rates." - severity = "high" - display_columns = ["endpoint", "error_count", "total_requests", "error_rate"] +detection "apache_missing_user_agent" { + title = "Missing User Agent Detected" + description = "Detect requests with missing user agent headers, which could indicate malicious tools or scripted attacks." + severity = "medium" + display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] - query = query.apache_error_rate_by_endpoint + query = query.apache_missing_user_agent tags = merge(local.apache_operational_common_tags, { - type = "Availability" + mitre_attack_id = "TA0043:T1592" # Reconnaissance:Gather Victim Host Information }) } -query "apache_error_rate_by_endpoint" { +query "apache_missing_user_agent" { sql = <<-EOQ select - request_uri as endpoint, - count(*) filter (where status >= 400) as error_count, - count(*) as total_requests, - round((count(*) filter (where status >= 400))::float / count(*)::numeric, 4) * 100 as error_rate + remote_addr as request_ip, + request_uri as request_path, + request_method, + status as status_code, + tp_timestamp as timestamp from apache_access_log where - request_uri is not null - and status is not null - group by - request_uri - having - count(*) >= 5 -- Minimum request threshold - and (count(*) filter (where status >= 400))::float / count(*) >= 0.1 -- 10% error rate threshold + http_user_agent is null + or http_user_agent = '-' + or http_user_agent = '' order by - error_rate desc, - total_requests desc; + tp_timestamp desc; EOQ } -detection "apache_client_error_analysis" { - title = "Client Error Analysis" - description = "Analyze patterns in client-side errors (4xx) to identify potential client issues." +detection "apache_large_payload_requests" { + title = "Large Payload Requests" + description = "Detect requests with unusually large body sizes that could indicate file uploads or data exfiltration." severity = "medium" - display_columns = ["status_code", "error_count", "percentage", "top_uri", "uri_count"] + display_columns = ["request_ip", "request_path", "request_method", "body_bytes", "status_code", "timestamp"] - query = query.apache_client_error_analysis + query = query.apache_large_payload_requests tags = merge(local.apache_operational_common_tags, { - type = "Availability" + mitre_attack_id = "TA0009:T1530,TA0010:T1048" # Collection:Data from Cloud Storage Object, Exfiltration:Exfiltration Over Alternative Protocol }) } -query "apache_client_error_analysis" { +query "apache_large_payload_requests" { sql = <<-EOQ - with client_errors as ( - select - status as status_code, - count(*) as error_count - from - apache_access_log - where - status >= 400 and status < 500 - group by - status - ), - error_uris as ( - select - status as status_code, - request_uri, - count(*) as uri_count, - row_number() over (partition by status order by count(*) desc) as rn - from - apache_access_log - where - status >= 400 and status < 500 - and request_uri is not null - group by - status, request_uri - ), - total_client_errors as ( - select sum(error_count) as total from client_errors - ) select - ce.status_code, - ce.error_count, - round((ce.error_count * 100.0 / tce.total)::numeric, 2) as percentage, - eu.request_uri as top_uri, - eu.uri_count + remote_addr as request_ip, + request_uri as request_path, + request_method, + body_bytes_sent as body_bytes, + status as status_code, + tp_timestamp as timestamp from - client_errors ce - join - total_client_errors tce on true - left join - error_uris eu on ce.status_code = eu.status_code and eu.rn = 1 + apache_access_log + where + body_bytes_sent > 10485760 -- Larger than 10MB order by - ce.error_count desc; + body_bytes_sent desc; EOQ } - -detection "apache_server_error_analysis" { - title = "Server Error Analysis" - description = "Analyze patterns in server-side errors (5xx) to identify potential server issues." - severity = "high" - display_columns = ["status_code", "error_count", "percentage", "top_uri", "uri_count"] - - query = query.apache_server_error_analysis - - tags = merge(local.apache_operational_common_tags, { - type = "Availability" - }) -} - -query "apache_server_error_analysis" { - sql = <<-EOQ - with server_errors as ( - select - status as status_code, - count(*) as error_count - from - apache_access_log - where - status >= 500 - group by - status - ), - error_uris as ( - select - status as status_code, - request_uri, - count(*) as uri_count, - row_number() over (partition by status order by count(*) desc) as rn - from - apache_access_log - where - status >= 500 - and request_uri is not null - group by - status, request_uri - ), - total_server_errors as ( - select sum(error_count) as total from server_errors - ) - select - se.status_code, - se.error_count, - round((se.error_count * 100.0 / tse.total)::numeric, 2) as percentage, - eu.request_uri as top_uri, - eu.uri_count - from - server_errors se - join - total_server_errors tse on true - left join - error_uris eu on se.status_code = eu.status_code and eu.rn = 1 - order by - se.error_count desc; - EOQ -} \ No newline at end of file diff --git a/detections/apache_performance.pp b/detections/apache_performance.pp index 924523d..aae2c46 100644 --- a/detections/apache_performance.pp +++ b/detections/apache_performance.pp @@ -9,10 +9,9 @@ description = "This benchmark contains performance-focused detections when scanning Apache access logs." type = "detection" children = [ - detection.apache_slow_response_time, - detection.apache_response_time_anomalies, - detection.apache_high_traffic_endpoints, - detection.apache_connection_pool_exhaustion + detection.apache_very_slow_requests, + detection.apache_large_static_file_requests, + detection.apache_timeout_errors ] tags = merge(local.apache_performance_common_tags, { @@ -20,185 +19,118 @@ }) } -detection "apache_slow_response_time" { - title = "Slow Response Time Detected" - description = "Detect endpoints with consistently high response times exceeding threshold." +detection "apache_very_slow_requests" { + title = "Very Slow HTTP Requests" + description = "Detect individual HTTP requests with abnormally high response times." severity = "high" - display_columns = ["endpoint", "avg_response_time", "request_count", "max_response_time"] + display_columns = ["request_ip", "request_path", "request_method", "response_time", "status_code", "timestamp"] - query = query.apache_slow_response_time + query = query.apache_very_slow_requests tags = merge(local.apache_performance_common_tags, { - type = "Latency" + mitre_attack_id = "TA0040:T1499.003" # Impact:Application Exhaustion Flood }) } -query "apache_slow_response_time" { +query "apache_very_slow_requests" { sql = <<-EOQ - with response_stats as ( - select - request_uri as endpoint, - count(*) as request_count, - avg(request_time) as avg_response_time, - max(request_time) as max_response_time - from - apache_access_log - where - request_uri is not null - and request_time > 0 - group by - request_uri - having - count(*) >= 5 -- Minimum request threshold - ) select - endpoint, - round(avg_response_time::numeric, 3) as avg_response_time, - request_count, - round(max_response_time::numeric, 3) as max_response_time + remote_addr as request_ip, + request_uri as request_path, + request_method, + request_time as response_time, + status as status_code, + tp_timestamp as timestamp from - response_stats + apache_access_log where - avg_response_time > 1 -- 1 second threshold - or max_response_time > 3 -- 3 second max threshold + request_time > 5 -- Requests taking more than 5 seconds order by - avg_response_time desc; + request_time desc; EOQ } -detection "apache_response_time_anomalies" { - title = "Response Time Anomalies Detected" - description = "Detect sudden increases in response time compared to historical patterns." - severity = "high" - display_columns = ["window_start", "window_end", "avg_response_time", "historical_avg", "deviation_percent"] - - query = query.apache_response_time_anomalies - - tags = merge(local.apache_performance_common_tags, { - type = "Anomaly" - }) -} - -query "apache_response_time_anomalies" { - sql = <<-EOQ - with time_windows as ( - select - time_bucket('5 minutes', tp_timestamp) as window_start, - time_bucket('5 minutes', tp_timestamp) + interval '5 minutes' as window_end, - avg(request_time) as avg_response_time, - avg(avg(request_time)) over ( - order by time_bucket('5 minutes', tp_timestamp) - rows between 12 preceding and 1 preceding - ) as historical_avg - from - apache_access_log - where - request_time > 0 - group by - time_bucket('5 minutes', tp_timestamp) - ) - select - window_start, - window_end, - round(avg_response_time::numeric, 3) as avg_response_time, - round(historical_avg::numeric, 3) as historical_avg, - round(((avg_response_time - historical_avg) / greatest(historical_avg, 0.001) * 100)::numeric, 2) as deviation_percent - from - time_windows - where - historical_avg > 0 - and ((avg_response_time - historical_avg) / greatest(historical_avg, 0.001)) > 0.5 -- 50% increase threshold - order by - window_start desc; - EOQ -} - -detection "apache_high_traffic_endpoints" { - title = "High Traffic Endpoints" - description = "Identify endpoints receiving unusually high traffic volumes." +detection "apache_large_static_file_requests" { + title = "Large Static File Requests" + description = "Detect requests for large static files that could impact server performance." severity = "medium" - display_columns = ["endpoint", "request_count", "traffic_percent", "avg_response_time"] + display_columns = ["request_ip", "request_path", "file_type", "body_bytes", "status_code", "timestamp"] - query = query.apache_high_traffic_endpoints + query = query.apache_large_static_file_requests tags = merge(local.apache_performance_common_tags, { - type = "Capacity" + mitre_attack_id = "TA0040:T1499.002" # Impact:Service Exhaustion Flood }) } -query "apache_high_traffic_endpoints" { +query "apache_large_static_file_requests" { sql = <<-EOQ - with endpoint_traffic as ( - select - request_uri as endpoint, - count(*) as request_count, - avg(request_time) as avg_response_time, - sum(bytes_sent) as total_bytes_sent - from - apache_access_log - where - request_uri is not null - group by - request_uri - ), - total_requests as ( - select sum(request_count) as total - from endpoint_traffic - ) select - endpoint, - request_count, - round((request_count * 100.0 / tr.total)::numeric, 2) as traffic_percent, - round(avg_response_time::numeric, 3) as avg_response_time + remote_addr as request_ip, + request_uri as request_path, + case + when lower(request_uri) like '%.jpg' or lower(request_uri) like '%.jpeg' then 'Image (JPEG)' + when lower(request_uri) like '%.png' then 'Image (PNG)' + when lower(request_uri) like '%.gif' then 'Image (GIF)' + when lower(request_uri) like '%.pdf' then 'Document (PDF)' + when lower(request_uri) like '%.mp4' or lower(request_uri) like '%.avi' or lower(request_uri) like '%.mov' then 'Video' + when lower(request_uri) like '%.mp3' or lower(request_uri) like '%.wav' then 'Audio' + when lower(request_uri) like '%.zip' or lower(request_uri) like '%.tar' or lower(request_uri) like '%.gz' then 'Archive' + else 'Other' + end as file_type, + body_bytes_sent as body_bytes, + status as status_code, + tp_timestamp as timestamp from - endpoint_traffic et - cross join - total_requests tr + apache_access_log where - request_count > 10 -- Minimum request threshold + body_bytes_sent > 5242880 -- Larger than 5MB + and ( + lower(request_uri) like '%.jpg' or + lower(request_uri) like '%.jpeg' or + lower(request_uri) like '%.png' or + lower(request_uri) like '%.gif' or + lower(request_uri) like '%.pdf' or + lower(request_uri) like '%.mp4' or + lower(request_uri) like '%.avi' or + lower(request_uri) like '%.mov' or + lower(request_uri) like '%.mp3' or + lower(request_uri) like '%.wav' or + lower(request_uri) like '%.zip' or + lower(request_uri) like '%.tar' or + lower(request_uri) like '%.gz' + ) order by - request_count desc - limit 10; + body_bytes_sent desc; EOQ } -detection "apache_connection_pool_exhaustion" { - title = "Connection Pool Exhaustion Risk" - description = "Detect risk of connection pool exhaustion based on concurrent connections." - severity = "critical" - display_columns = ["timestamp", "concurrent_connections", "rejection_rate"] +detection "apache_timeout_errors" { + title = "Request Timeout Errors" + description = "Detect HTTP 408 Request Timeout or 504 Gateway Timeout errors indicating resource constraints." + severity = "high" + display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] - query = query.apache_connection_pool_exhaustion + query = query.apache_timeout_errors tags = merge(local.apache_performance_common_tags, { - type = "Capacity" + mitre_attack_id = "TA0040:T1499.004" # Impact:Application or System Exploitation }) } -query "apache_connection_pool_exhaustion" { +query "apache_timeout_errors" { sql = <<-EOQ - with connection_stats as ( - select - time_bucket('1 minute', tp_timestamp) as timestamp, - count(*) as concurrent_connections, - count(*) filter (where status = 503) / nullif(count(*), 0)::float * 100 as rejection_rate - from - apache_access_log - where - status is not null - group by - time_bucket('1 minute', tp_timestamp) - ) select - timestamp, - concurrent_connections, - round(rejection_rate::numeric, 2) as rejection_rate + remote_addr as request_ip, + request_uri as request_path, + request_method, + status as status_code, + tp_timestamp as timestamp from - connection_stats + apache_access_log where - concurrent_connections > 100 -- Adjust based on server capacity - or rejection_rate > 5 -- 5% rejection rate threshold + status in (408, 504) -- Request Timeout or Gateway Timeout order by - timestamp desc; + tp_timestamp desc; EOQ -} \ No newline at end of file +} diff --git a/detections/apache_security.pp b/detections/apache_security.pp index 8947955..27d3265 100644 --- a/detections/apache_security.pp +++ b/detections/apache_security.pp @@ -11,13 +11,11 @@ children = [ detection.apache_sql_injection_attempts, detection.apache_directory_traversal_attempts, - detection.apache_brute_force_auth_attempts, detection.apache_suspicious_user_agents, detection.apache_xss_attempts, detection.apache_sensitive_file_access, detection.apache_unusual_http_methods, detection.apache_web_shell_detection, - # detection.apache_log4j_exploitation_attempts, detection.apache_api_key_exposure ] @@ -107,48 +105,6 @@ EOQ } -detection "apache_brute_force_auth_attempts" { - title = "Authentication Brute Force Attempts" - description = "Detect potential brute force authentication attempts based on high frequency of 401/403 errors from the same IP." - severity = "high" - display_columns = ["request_ip", "target_path", "failed_attempts", "first_attempt", "last_attempt"] - - query = query.apache_brute_force_auth_attempts - - tags = merge(local.apache_security_common_tags, { - mitre_attack_ids = "TA0006:T1110" - }) -} - -query "apache_brute_force_auth_attempts" { - sql = <<-EOQ - with failed_auths as ( - select - remote_addr as request_ip, - request_uri as target_path, - count(*) as failed_attempts, - min(tp_timestamp) as first_attempt, - max(tp_timestamp) as last_attempt - from - apache_access_log - where - status in (401, 403) - and request_uri is not null - group by - remote_addr, request_uri - having - count(*) >= 5 - and (max(tp_timestamp) - min(tp_timestamp)) <= interval '5 minutes' - ) - select - * - from - failed_auths - order by - failed_attempts desc; - EOQ -} - detection "apache_suspicious_user_agents" { title = "Suspicious User Agents Detected" description = "Detect requests from known malicious or suspicious user agents." @@ -381,51 +337,6 @@ EOQ } -# detection "apache_log4j_exploitation_attempts" { -# title = "Log4j Exploitation Attempts" -# description = "Detect potential Log4j/Log4Shell exploitation attempts in request parameters." -# severity = "critical" -# display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] - -# query = query.apache_log4j_exploitation_attempts - -# tags = merge(local.apache_security_common_tags, { -# mitre_attack_ids = "TA0002:T1190" -# }) -# } - -# query "apache_log4j_exploitation_attempts" { -# sql = <<-EOQ -# select -# remote_addr as request_ip, -# request_uri as request_path, -# request_method, -# status as status_code, -# tp_timestamp as timestamp -# from -# apache_access_log -# where -# ( -# request_uri is not null -# and ( -# lower(request_uri) like '%${jndi : % ' -# or lower(request_uri) like ' % $ % 7 bjndi : % ' -# or lower(request_uri) like ' % $ { % ' -# or lower(request_uri) like ' % $ % 7 b % ' -# ) -# ) -# or( -# http_user_agent is not null -# and( -# lower(http_user_agent) like ' % $ { jndi : % ' -# or lower(http_user_agent) like ' % $ % 7 bjndi : % ' -# ) -# ) -# order by -# tp_timestamp desc; -# EOQ -# } - detection "apache_api_key_exposure" { title = "API Key or Token Exposure" description = "Detect potential exposure of API keys or tokens in URLs." diff --git a/mitre_attack_v161/docs/mitre.md b/mitre_attack_v161/docs/mitre.md new file mode 100644 index 0000000..694debd --- /dev/null +++ b/mitre_attack_v161/docs/mitre.md @@ -0,0 +1,5 @@ +To obtain the latest version of this official guide, please visit https://attack.mitre.org/. + +## Overview + +MITRE ATT&CK is a globally-accessible knowledge base of adversary tactics and techniques based on real-world observations. The ATT&CK knowledge base is used as a foundation for the development of specific threat models and methodologies in the private sector, in government, and in the cybersecurity product and service community. diff --git a/mitre_attack_v161/mitre.pp b/mitre_attack_v161/mitre.pp new file mode 100644 index 0000000..b8002a8 --- /dev/null +++ b/mitre_attack_v161/mitre.pp @@ -0,0 +1,19 @@ +locals { + mitre_attack_v161_common_tags = merge(local.apache_access_log_detections_common_tags, { + mitre_attack_version = "v16.1" + }) +} + +benchmark "mitre_attack_v161" { + title = "MITRE ATT&CK v16.1" + description = "MITRE ATT&CK is a globally-accessible knowledge base of adversary tactics and techniques based on real-world observations." + type = "detection" + documentation = file("./mitre_attack_v161/docs/mitre.md") + children = [ + + ] + + tags = merge(local.mitre_attack_v161_common_tags, { + type = "Benchmark" + }) +} From 86822b967686d0fc1b41998938b7b8a24dad9267 Mon Sep 17 00:00:00 2001 From: Priyanka Chatterjee Date: Thu, 3 Apr 2025 18:52:31 +0530 Subject: [PATCH 04/62] Add back the detections using agregated queries --- detections/apache_compliance.pp | 93 +++++++++++- detections/apache_operational.pp | 253 ++++++++++++++++++++++++++++++- detections/apache_performance.pp | 189 ++++++++++++++++++++++- detections/apache_security.pp | 52 +++++++ 4 files changed, 584 insertions(+), 3 deletions(-) diff --git a/detections/apache_compliance.pp b/detections/apache_compliance.pp index 5cd93a4..03d0b48 100644 --- a/detections/apache_compliance.pp +++ b/detections/apache_compliance.pp @@ -10,7 +10,9 @@ type = "detection" children = [ detection.apache_pii_data_exposure, - detection.apache_restricted_resource_access + detection.apache_restricted_resource_access, + detection.apache_unauthorized_ip_access, + detection.apache_data_privacy_requirements ] tags = merge(local.apache_compliance_common_tags, { @@ -112,4 +114,93 @@ order by timestamp desc; EOQ +} + +detection "apache_unauthorized_ip_access" { + title = "Unauthorized IP Range Access" + description = "Detect access attempts from unauthorized IP ranges or geographic locations." + severity = "high" + display_columns = ["request_ip", "request_count", "first_access", "last_access"] + + query = query.apache_unauthorized_ip_access + + tags = merge(local.apache_compliance_common_tags, { + mitre_attack_id = "TA0008:T1133,TA0003:T1078.004" # Lateral Movement:External Remote Services, Persistence:Cloud Accounts + }) +} + +query "apache_unauthorized_ip_access" { + sql = <<-EOQ + with unauthorized_access as ( + select + remote_addr as request_ip, + count(*) as request_count, + min(tp_timestamp) as first_access, + max(tp_timestamp) as last_access + from + apache_access_log + where + remote_addr not like '10.%' + and remote_addr not like '172.%' + and remote_addr not like '192.168.%' + and remote_addr not like '127.%' + group by + remote_addr + ) + select + * + from + unauthorized_access + order by + request_count desc; + EOQ +} + +detection "apache_data_privacy_requirements" { + title = "Data Privacy Requirements" + description = "Monitor compliance with data privacy requirements and sensitive data handling." + severity = "high" + display_columns = ["endpoint", "total_requests", "sensitive_data_count", "unique_ips"] + + query = query.apache_data_privacy_requirements + + tags = merge(local.apache_compliance_common_tags, { + mitre_attack_id = "TA0009:T1530,TA0006:T1552.001" # Collection:Data from Cloud Storage, Credential Access:Credentials In Files + }) +} + +query "apache_data_privacy_requirements" { + sql = <<-EOQ + with privacy_endpoints as ( + select + request_uri as endpoint, + count(*) as total_requests, + count(*) filter ( + where request_uri ~ '(?i)(ssn|email|password|credit|card|phone|address|dob|birth)' + ) as sensitive_data_count, + count(distinct remote_addr) as unique_ips + from + apache_access_log + where + request_uri is not null + -- Focus on API endpoints and form submissions + and (request_uri like '/api/%' or request_method = 'POST') + group by + request_uri + having + count(*) filter ( + where request_uri ~ '(?i)(ssn|email|password|credit|card|phone|address|dob|birth)' + ) > 0 + ) + select + endpoint, + total_requests, + sensitive_data_count, + unique_ips, + round((sensitive_data_count::float / total_requests * 100)::numeric, 2) as sensitive_data_percentage + from + privacy_endpoints + order by + sensitive_data_count desc; + EOQ } \ No newline at end of file diff --git a/detections/apache_operational.pp b/detections/apache_operational.pp index 987f803..3c4c83f 100644 --- a/detections/apache_operational.pp +++ b/detections/apache_operational.pp @@ -11,7 +11,12 @@ children = [ detection.apache_status_500_errors, detection.apache_missing_user_agent, - detection.apache_large_payload_requests + detection.apache_large_payload_requests, + detection.apache_high_error_rate, + detection.apache_unusual_traffic_spike, + detection.apache_error_rate_by_endpoint, + detection.apache_client_error_analysis, + detection.apache_server_error_analysis ] tags = merge(local.apache_operational_common_tags, { @@ -111,3 +116,249 @@ body_bytes_sent desc; EOQ } + +detection "apache_high_error_rate" { + title = "High Error Rate Detected" + description = "Detect when the rate of HTTP errors exceeds a threshold within a time window." + severity = "high" + display_columns = ["error_count", "total_requests", "error_rate", "window_start", "window_end"] + + query = query.apache_high_error_rate + + tags = merge(local.apache_operational_common_tags, { + mitre_attack_id = "TA0040:T1499.002" # Impact:Service Exhaustion Flood + }) +} + +query "apache_high_error_rate" { + sql = <<-EOQ + with error_windows as ( + select + count(*) filter (where status >= 400) as error_count, + count(*) as total_requests, + (count(*) filter (where status >= 400))::float / count(*) as error_rate, + time_bucket('5 minutes', tp_timestamp) as window_start, + time_bucket('5 minutes', tp_timestamp) + interval '5 minutes' as window_end + from + apache_access_log + where + status is not null + group by + time_bucket('5 minutes', tp_timestamp) + having + count(*) >= 10 -- Minimum request threshold + and (count(*) filter (where status >= 400))::float / count(*) >= 0.1 -- 10% error rate threshold + ) + select + error_count, + total_requests, + round((error_rate * 100)::numeric, 2) as error_rate, + window_start, + window_end + from + error_windows + order by + window_start desc; + EOQ +} + +detection "apache_unusual_traffic_spike" { + title = "Unusual Traffic Spike Detected" + description = "Detect unusual spikes in traffic volume compared to historical patterns." + severity = "medium" + display_columns = ["request_count", "avg_historical_requests", "deviation_percent", "window_start", "window_end"] + + query = query.apache_unusual_traffic_spike + + tags = merge(local.apache_operational_common_tags, { + mitre_attack_id = "TA0040:T1498,TA0040:T1499.002" # Impact:Network Denial of Service, Impact:Service Exhaustion Flood + }) +} + +query "apache_unusual_traffic_spike" { + sql = <<-EOQ + with traffic_windows as ( + select + count(*) as request_count, + time_bucket('5 minutes', tp_timestamp) as window_start, + avg(count(*)) over ( + order by time_bucket('5 minutes', tp_timestamp) + rows between 12 preceding and 1 preceding + ) as avg_historical_requests, + time_bucket('5 minutes', tp_timestamp) + interval '5 minutes' as window_end + from + apache_access_log + group by + time_bucket('5 minutes', tp_timestamp) + ) + select + request_count, + round(avg_historical_requests::numeric, 2) as avg_historical_requests, + round(((request_count - avg_historical_requests) / greatest(avg_historical_requests, 1) * 100)::numeric, 2) as deviation_percent, + window_start, + window_end + from + traffic_windows + where + avg_historical_requests > 0 + and ((request_count - avg_historical_requests) / greatest(avg_historical_requests, 1)) > 1 -- 100% increase threshold + order by + window_start desc; + EOQ +} + +detection "apache_error_rate_by_endpoint" { + title = "High Error Rate by Endpoint" + description = "Detect endpoints with unusually high error rates." + severity = "high" + display_columns = ["endpoint", "error_count", "total_requests", "error_rate"] + + query = query.apache_error_rate_by_endpoint + + tags = merge(local.apache_operational_common_tags, { + mitre_attack_id = "TA0040:T1499.002,TA0001:T1190" # Impact:Service Exhaustion Flood, Initial Access:Exploit Public-Facing Application + }) +} + +query "apache_error_rate_by_endpoint" { + sql = <<-EOQ + select + request_uri as endpoint, + count(*) filter (where status >= 400) as error_count, + count(*) as total_requests, + round((count(*) filter (where status >= 400))::float / count(*)::numeric, 4) * 100 as error_rate + from + apache_access_log + where + request_uri is not null + and status is not null + group by + request_uri + having + count(*) >= 5 -- Minimum request threshold + and (count(*) filter (where status >= 400))::float / count(*) >= 0.1 -- 10% error rate threshold + order by + error_rate desc, + total_requests desc; + EOQ +} + +detection "apache_client_error_analysis" { + title = "Client Error Analysis" + description = "Analyze patterns in client-side errors (4xx) to identify potential client issues." + severity = "medium" + display_columns = ["status_code", "error_count", "percentage", "top_uri", "uri_count"] + + query = query.apache_client_error_analysis + + tags = merge(local.apache_operational_common_tags, { + mitre_attack_id = "TA0001:T1190,TA0043:T1595" # Initial Access:Exploit Public-Facing Application, Reconnaissance:Active Scanning + }) +} + +query "apache_client_error_analysis" { + sql = <<-EOQ + with client_errors as ( + select + status as status_code, + count(*) as error_count + from + apache_access_log + where + status >= 400 and status < 500 + group by + status + ), + error_uris as ( + select + status as status_code, + request_uri, + count(*) as uri_count, + row_number() over (partition by status order by count(*) desc) as rn + from + apache_access_log + where + status >= 400 and status < 500 + and request_uri is not null + group by + status, request_uri + ), + total_client_errors as ( + select sum(error_count) as total from client_errors + ) + select + ce.status_code, + ce.error_count, + round((ce.error_count * 100.0 / tce.total)::numeric, 2) as percentage, + eu.request_uri as top_uri, + eu.uri_count + from + client_errors ce + join + total_client_errors tce on true + left join + error_uris eu on ce.status_code = eu.status_code and eu.rn = 1 + order by + ce.error_count desc; + EOQ +} + +detection "apache_server_error_analysis" { + title = "Server Error Analysis" + description = "Analyze patterns in server-side errors (5xx) to identify potential server issues." + severity = "high" + display_columns = ["status_code", "error_count", "percentage", "top_uri", "uri_count"] + + query = query.apache_server_error_analysis + + tags = merge(local.apache_operational_common_tags, { + mitre_attack_id = "TA0040:T1499.004,TA0040:T1499.003" # Impact:Application or System Exploitation, Impact:Application Exhaustion Flood + }) +} + +query "apache_server_error_analysis" { + sql = <<-EOQ + with server_errors as ( + select + status as status_code, + count(*) as error_count + from + apache_access_log + where + status >= 500 + group by + status + ), + error_uris as ( + select + status as status_code, + request_uri, + count(*) as uri_count, + row_number() over (partition by status order by count(*) desc) as rn + from + apache_access_log + where + status >= 500 + and request_uri is not null + group by + status, request_uri + ), + total_server_errors as ( + select sum(error_count) as total from server_errors + ) + select + se.status_code, + se.error_count, + round((se.error_count * 100.0 / tse.total)::numeric, 2) as percentage, + eu.request_uri as top_uri, + eu.uri_count + from + server_errors se + join + total_server_errors tse on true + left join + error_uris eu on se.status_code = eu.status_code and eu.rn = 1 + order by + se.error_count desc; + EOQ +} diff --git a/detections/apache_performance.pp b/detections/apache_performance.pp index aae2c46..369979f 100644 --- a/detections/apache_performance.pp +++ b/detections/apache_performance.pp @@ -11,7 +11,11 @@ children = [ detection.apache_very_slow_requests, detection.apache_large_static_file_requests, - detection.apache_timeout_errors + detection.apache_timeout_errors, + detection.apache_slow_response_time, + detection.apache_response_time_anomalies, + detection.apache_high_traffic_endpoints, + detection.apache_connection_pool_exhaustion ] tags = merge(local.apache_performance_common_tags, { @@ -134,3 +138,186 @@ tp_timestamp desc; EOQ } + +detection "apache_slow_response_time" { + title = "Slow Response Time Detected" + description = "Detect endpoints with consistently high response times exceeding threshold." + severity = "high" + display_columns = ["endpoint", "avg_response_time", "request_count", "max_response_time"] + + query = query.apache_slow_response_time + + tags = merge(local.apache_performance_common_tags, { + mitre_attack_id = "TA0040:T1499.003,TA0040:T1496.001" # Impact:Application Exhaustion Flood, Impact:Compute Hijacking + }) +} + +query "apache_slow_response_time" { + sql = <<-EOQ + with response_stats as ( + select + request_uri as endpoint, + count(*) as request_count, + avg(request_time) as avg_response_time, + max(request_time) as max_response_time + from + apache_access_log + where + request_uri is not null + and request_time > 0 + group by + request_uri + having + count(*) >= 5 -- Minimum request threshold + ) + select + endpoint, + round(avg_response_time::numeric, 3) as avg_response_time, + request_count, + round(max_response_time::numeric, 3) as max_response_time + from + response_stats + where + avg_response_time > 1 -- 1 second threshold + or max_response_time > 3 -- 3 second max threshold + order by + avg_response_time desc; + EOQ +} + +detection "apache_response_time_anomalies" { + title = "Response Time Anomalies Detected" + description = "Detect sudden increases in response time compared to historical patterns." + severity = "high" + display_columns = ["window_start", "window_end", "avg_response_time", "historical_avg", "deviation_percent"] + + query = query.apache_response_time_anomalies + + tags = merge(local.apache_performance_common_tags, { + mitre_attack_id = "TA0040:T1499.003,TA0040:T1496.001" # Impact:Application Exhaustion Flood, Impact:Compute Hijacking + }) +} + +query "apache_response_time_anomalies" { + sql = <<-EOQ + with time_windows as ( + select + time_bucket('5 minutes', tp_timestamp) as window_start, + time_bucket('5 minutes', tp_timestamp) + interval '5 minutes' as window_end, + avg(request_time) as avg_response_time, + avg(avg(request_time)) over ( + order by time_bucket('5 minutes', tp_timestamp) + rows between 12 preceding and 1 preceding + ) as historical_avg + from + apache_access_log + where + request_time > 0 + group by + time_bucket('5 minutes', tp_timestamp) + ) + select + window_start, + window_end, + round(avg_response_time::numeric, 3) as avg_response_time, + round(historical_avg::numeric, 3) as historical_avg, + round(((avg_response_time - historical_avg) / greatest(historical_avg, 0.001) * 100)::numeric, 2) as deviation_percent + from + time_windows + where + historical_avg > 0 + and ((avg_response_time - historical_avg) / greatest(historical_avg, 0.001)) > 0.5 -- 50% increase threshold + order by + window_start desc; + EOQ +} + +detection "apache_high_traffic_endpoints" { + title = "High Traffic Endpoints" + description = "Identify endpoints receiving unusually high traffic volumes." + severity = "medium" + display_columns = ["endpoint", "request_count", "traffic_percent", "avg_response_time"] + + query = query.apache_high_traffic_endpoints + + tags = merge(local.apache_performance_common_tags, { + mitre_attack_id = "TA0040:T1499.002,TA0040:T1498.001" # Impact:Service Exhaustion Flood, Impact:Direct Network Flood + }) +} + +query "apache_high_traffic_endpoints" { + sql = <<-EOQ + with endpoint_traffic as ( + select + request_uri as endpoint, + count(*) as request_count, + avg(request_time) as avg_response_time, + sum(bytes_sent) as total_bytes_sent + from + apache_access_log + where + request_uri is not null + group by + request_uri + ), + total_requests as ( + select sum(request_count) as total + from endpoint_traffic + ) + select + endpoint, + request_count, + round((request_count * 100.0 / tr.total)::numeric, 2) as traffic_percent, + round(avg_response_time::numeric, 3) as avg_response_time + from + endpoint_traffic et + cross join + total_requests tr + where + request_count > 10 -- Minimum request threshold + order by + request_count desc + limit 10; + EOQ +} + +detection "apache_connection_pool_exhaustion" { + title = "Connection Pool Exhaustion Risk" + description = "Detect risk of connection pool exhaustion based on concurrent connections." + severity = "critical" + display_columns = ["timestamp", "concurrent_connections", "rejection_rate"] + + query = query.apache_connection_pool_exhaustion + + tags = merge(local.apache_performance_common_tags, { + mitre_attack_id = "TA0040:T1499.002" # Impact:Service Exhaustion Flood + }) +} + +query "apache_connection_pool_exhaustion" { + sql = <<-EOQ + with connection_stats as ( + select + time_bucket('1 minute', tp_timestamp) as timestamp, + count(*) as concurrent_connections, + count(*) filter (where status = 503) / nullif(count(*), 0)::float * 100 as rejection_rate + from + apache_access_log + where + status is not null + group by + time_bucket('1 minute', tp_timestamp) + ) + select + timestamp, + concurrent_connections, + round(rejection_rate::numeric, 2) as rejection_rate + from + connection_stats + where + concurrent_connections > 100 -- Adjust based on server capacity + or rejection_rate > 5 -- 5% rejection rate threshold + order by + timestamp desc; + EOQ +} diff --git a/detections/apache_security.pp b/detections/apache_security.pp index 27d3265..e1f3e68 100644 --- a/detections/apache_security.pp +++ b/detections/apache_security.pp @@ -11,6 +11,7 @@ children = [ detection.apache_sql_injection_attempts, detection.apache_directory_traversal_attempts, + detection.apache_brute_force_auth_attempts, detection.apache_suspicious_user_agents, detection.apache_xss_attempts, detection.apache_sensitive_file_access, @@ -105,6 +106,57 @@ EOQ } +detection "apache_brute_force_auth_attempts" { + title = "Brute Force Authentication Attempts Detected" + description = "Detect potential brute force authentication attempts." + severity = "high" + display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] + + query = query.apache_brute_force_auth_attempts + + tags = merge(local.apache_security_common_tags, { + mitre_attack_ids = "TA0009:T1110" + }) +} + +query "apache_brute_force_auth_attempts" { + sql = <<-EOQ + select + remote_addr as request_ip, + request_uri as request_path, + request_method, + status as status_code, + tp_timestamp as timestamp + from + apache_access_log + where + request_uri is not null + and ( + -- Common brute force patterns + lower(request_uri) like '%login%' + or lower(request_uri) like '%auth%' + or lower(request_uri) like '%pass%' + or lower(request_uri) like '%password%' + or lower(request_uri) like '%user%' + or lower(request_uri) like '%username%' + or lower(request_uri) like '%credentials%' + or lower(request_uri) like '%attempt%' + or lower(request_uri) like '%failed%' + or lower(request_uri) like '%error%' + ) + and ( + -- Successful response increases suspicion + status = 200 + -- POST to these URLs is suspicious + or request_method = 'POST' + -- PUT to these URLs is very suspicious + or request_method = 'PUT' + ) + order by + tp_timestamp desc; + EOQ +} + detection "apache_suspicious_user_agents" { title = "Suspicious User Agents Detected" description = "Detect requests from known malicious or suspicious user agents." From 38806d296e6df23fb4dfa8c1e2efd517655b850d Mon Sep 17 00:00:00 2001 From: Priyanka Chatterjee Date: Fri, 4 Apr 2025 15:11:51 +0530 Subject: [PATCH 05/62] Remove Apache Activity Dashboard and associated documentation; update Apache detection modules with new naming conventions and improved descriptions for clarity and consistency. --- ...ity_dashboard.pp => activity_dashboard.pp} | 0 ...ity_dashboard.md => activity_dashboard.md} | 0 detections/apache_compliance.pp | 48 ++++---- detections/apache_operational.pp | 96 ++++++++-------- detections/apache_performance.pp | 84 +++++++------- detections/apache_security.pp | 108 +++++++++--------- 6 files changed, 168 insertions(+), 168 deletions(-) rename dashboards/{apache_activity_dashboard.pp => activity_dashboard.pp} (100%) rename dashboards/docs/{apache_activity_dashboard.md => activity_dashboard.md} (100%) diff --git a/dashboards/apache_activity_dashboard.pp b/dashboards/activity_dashboard.pp similarity index 100% rename from dashboards/apache_activity_dashboard.pp rename to dashboards/activity_dashboard.pp diff --git a/dashboards/docs/apache_activity_dashboard.md b/dashboards/docs/activity_dashboard.md similarity index 100% rename from dashboards/docs/apache_activity_dashboard.md rename to dashboards/docs/activity_dashboard.md diff --git a/detections/apache_compliance.pp b/detections/apache_compliance.pp index 03d0b48..fd34b60 100644 --- a/detections/apache_compliance.pp +++ b/detections/apache_compliance.pp @@ -9,10 +9,10 @@ description = "This benchmark contains compliance-focused detections when scanning Apache access logs." type = "detection" children = [ - detection.apache_pii_data_exposure, - detection.apache_restricted_resource_access, - detection.apache_unauthorized_ip_access, - detection.apache_data_privacy_requirements + detection.apache_pii_data_exposed_in_url, + detection.apache_restricted_resource_accessed, + detection.apache_unauthorized_ip_access_detected, + detection.apache_data_privacy_requirement_violated ] tags = merge(local.apache_compliance_common_tags, { @@ -20,20 +20,20 @@ }) } -detection "apache_pii_data_exposure" { - title = "PII Data Exposure in URLs" - description = "Detect potential exposure of Personally Identifiable Information (PII) in URLs." +detection "apache_pii_data_exposed_in_url" { + title = "Apache PII Data Exposed In URL" + description = "Detect when an Apache web server logged Personally Identifiable Information (PII) in URLs to check for potential data privacy violations, regulatory non-compliance, and sensitive information disclosure." severity = "critical" display_columns = ["request_ip", "request_path", "pii_type", "status_code", "timestamp"] - query = query.apache_pii_data_exposure + query = query.apache_pii_data_exposed_in_url tags = merge(local.apache_compliance_common_tags, { mitre_attack_id = "TA0006:T1552.001" # Credential Access:Credentials In Files }) } -query "apache_pii_data_exposure" { +query "apache_pii_data_exposed_in_url" { sql = <<-EOQ with pii_patterns as ( select @@ -69,20 +69,20 @@ EOQ } -detection "apache_restricted_resource_access" { - title = "Restricted Resource Access" - description = "Detect access attempts to restricted resources or administrative areas." +detection "apache_restricted_resource_accessed" { + title = "Apache Restricted Resource Accessed" + description = "Detect when an Apache web server processed requests to restricted resources or administrative areas to check for unauthorized access attempts, privilege escalation, or security policy violations." severity = "high" display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] - query = query.apache_restricted_resource_access + query = query.apache_restricted_resource_accessed tags = merge(local.apache_compliance_common_tags, { mitre_attack_id = "TA0001:T1190,TA0008:T1133" # Initial Access:Exploit Public-Facing Application, Lateral Movement:External Remote Services }) } -query "apache_restricted_resource_access" { +query "apache_restricted_resource_accessed" { sql = <<-EOQ select remote_addr as request_ip, @@ -116,20 +116,20 @@ EOQ } -detection "apache_unauthorized_ip_access" { - title = "Unauthorized IP Range Access" - description = "Detect access attempts from unauthorized IP ranges or geographic locations." +detection "apache_unauthorized_ip_access_detected" { + title = "Apache Unauthorized IP Access Detected" + description = "Detect when an Apache web server received requests from unauthorized IP ranges or geographic locations to check for potential security policy violations, access control bypasses, or geofencing compliance issues." severity = "high" display_columns = ["request_ip", "request_count", "first_access", "last_access"] - query = query.apache_unauthorized_ip_access + query = query.apache_unauthorized_ip_access_detected tags = merge(local.apache_compliance_common_tags, { mitre_attack_id = "TA0008:T1133,TA0003:T1078.004" # Lateral Movement:External Remote Services, Persistence:Cloud Accounts }) } -query "apache_unauthorized_ip_access" { +query "apache_unauthorized_ip_access_detected" { sql = <<-EOQ with unauthorized_access as ( select @@ -156,20 +156,20 @@ EOQ } -detection "apache_data_privacy_requirements" { - title = "Data Privacy Requirements" - description = "Monitor compliance with data privacy requirements and sensitive data handling." +detection "apache_data_privacy_requirement_violated" { + title = "Apache Data Privacy Requirement Violated" + description = "Detect when an Apache web server processed requests that potentially violate data privacy requirements to check for regulatory compliance issues, sensitive data handling violations, or privacy policy infractions." severity = "high" display_columns = ["endpoint", "total_requests", "sensitive_data_count", "unique_ips"] - query = query.apache_data_privacy_requirements + query = query.apache_data_privacy_requirement_violated tags = merge(local.apache_compliance_common_tags, { mitre_attack_id = "TA0009:T1530,TA0006:T1552.001" # Collection:Data from Cloud Storage, Credential Access:Credentials In Files }) } -query "apache_data_privacy_requirements" { +query "apache_data_privacy_requirement_violated" { sql = <<-EOQ with privacy_endpoints as ( select diff --git a/detections/apache_operational.pp b/detections/apache_operational.pp index 3c4c83f..a23e30b 100644 --- a/detections/apache_operational.pp +++ b/detections/apache_operational.pp @@ -9,14 +9,14 @@ description = "This benchmark contains operational detections when scanning Apache access logs." type = "detection" children = [ - detection.apache_status_500_errors, - detection.apache_missing_user_agent, - detection.apache_large_payload_requests, - detection.apache_high_error_rate, - detection.apache_unusual_traffic_spike, - detection.apache_error_rate_by_endpoint, - detection.apache_client_error_analysis, - detection.apache_server_error_analysis + detection.apache_internal_server_error_occurred, + detection.apache_missing_user_agent_detected, + detection.apache_large_payload_request_detected, + detection.apache_high_error_rate_detected, + detection.apache_unusual_traffic_spike_detected, + detection.apache_endpoint_high_error_rate_detected, + detection.apache_client_error_pattern_detected, + detection.apache_server_error_pattern_detected ] tags = merge(local.apache_operational_common_tags, { @@ -24,20 +24,20 @@ }) } -detection "apache_status_500_errors" { - title = "HTTP 500 Internal Server Errors" - description = "Detect individual HTTP 500 Internal Server Error responses that indicate server-side failures." +detection "apache_internal_server_error_occurred" { + title = "Apache Internal Server Error Occurred" + description = "Detect when an Apache web server returned HTTP 500 Internal Server Error responses to check for server-side failures, application crashes, or misconfiguration issues." severity = "high" display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] - query = query.apache_status_500_errors + query = query.apache_internal_server_error_occurred tags = merge(local.apache_operational_common_tags, { mitre_attack_id = "TA0040:T1499.004" # Impact:Application or System Exploitation }) } -query "apache_status_500_errors" { +query "apache_internal_server_error_occurred" { sql = <<-EOQ select remote_addr as request_ip, @@ -54,20 +54,20 @@ EOQ } -detection "apache_missing_user_agent" { - title = "Missing User Agent Detected" - description = "Detect requests with missing user agent headers, which could indicate malicious tools or scripted attacks." +detection "apache_missing_user_agent_detected" { + title = "Apache Missing User Agent Detected" + description = "Detect when an Apache web server received requests with missing user agent headers to check for potential automated tools, scripted attacks, or non-standard clients." severity = "medium" display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] - query = query.apache_missing_user_agent + query = query.apache_missing_user_agent_detected tags = merge(local.apache_operational_common_tags, { mitre_attack_id = "TA0043:T1592" # Reconnaissance:Gather Victim Host Information }) } -query "apache_missing_user_agent" { +query "apache_missing_user_agent_detected" { sql = <<-EOQ select remote_addr as request_ip, @@ -86,20 +86,20 @@ EOQ } -detection "apache_large_payload_requests" { - title = "Large Payload Requests" - description = "Detect requests with unusually large body sizes that could indicate file uploads or data exfiltration." +detection "apache_large_payload_request_detected" { + title = "Apache Large Payload Request Detected" + description = "Detect when an Apache web server processed requests with unusually large body sizes to check for potential file uploads, data exfiltration attempts, or resource consumption issues." severity = "medium" display_columns = ["request_ip", "request_path", "request_method", "body_bytes", "status_code", "timestamp"] - query = query.apache_large_payload_requests + query = query.apache_large_payload_request_detected tags = merge(local.apache_operational_common_tags, { mitre_attack_id = "TA0009:T1530,TA0010:T1048" # Collection:Data from Cloud Storage Object, Exfiltration:Exfiltration Over Alternative Protocol }) } -query "apache_large_payload_requests" { +query "apache_large_payload_request_detected" { sql = <<-EOQ select remote_addr as request_ip, @@ -117,20 +117,20 @@ EOQ } -detection "apache_high_error_rate" { - title = "High Error Rate Detected" - description = "Detect when the rate of HTTP errors exceeds a threshold within a time window." +detection "apache_high_error_rate_detected" { + title = "Apache High Error Rate Detected" + description = "Detect when an Apache web server experienced a high rate of HTTP errors within a time window to check for potential service disruptions, application failures, or attack patterns." severity = "high" display_columns = ["error_count", "total_requests", "error_rate", "window_start", "window_end"] - query = query.apache_high_error_rate + query = query.apache_high_error_rate_detected tags = merge(local.apache_operational_common_tags, { mitre_attack_id = "TA0040:T1499.002" # Impact:Service Exhaustion Flood }) } -query "apache_high_error_rate" { +query "apache_high_error_rate_detected" { sql = <<-EOQ with error_windows as ( select @@ -162,20 +162,20 @@ EOQ } -detection "apache_unusual_traffic_spike" { - title = "Unusual Traffic Spike Detected" - description = "Detect unusual spikes in traffic volume compared to historical patterns." +detection "apache_unusual_traffic_spike_detected" { + title = "Apache Unusual Traffic Spike Detected" + description = "Detect when an Apache web server experienced unusual spikes in traffic volume compared to historical patterns to check for potential DDoS attacks, viral content, or unexpected application behavior." severity = "medium" display_columns = ["request_count", "avg_historical_requests", "deviation_percent", "window_start", "window_end"] - query = query.apache_unusual_traffic_spike + query = query.apache_unusual_traffic_spike_detected tags = merge(local.apache_operational_common_tags, { mitre_attack_id = "TA0040:T1498,TA0040:T1499.002" # Impact:Network Denial of Service, Impact:Service Exhaustion Flood }) } -query "apache_unusual_traffic_spike" { +query "apache_unusual_traffic_spike_detected" { sql = <<-EOQ with traffic_windows as ( select @@ -207,20 +207,20 @@ EOQ } -detection "apache_error_rate_by_endpoint" { - title = "High Error Rate by Endpoint" - description = "Detect endpoints with unusually high error rates." +detection "apache_endpoint_high_error_rate_detected" { + title = "Apache Endpoint High Error Rate Detected" + description = "Detect when an Apache web server processed requests to specific endpoints with unusually high error rates to check for broken functionality, misconfiguration, or targeted attacks against specific application components." severity = "high" display_columns = ["endpoint", "error_count", "total_requests", "error_rate"] - query = query.apache_error_rate_by_endpoint + query = query.apache_endpoint_high_error_rate_detected tags = merge(local.apache_operational_common_tags, { mitre_attack_id = "TA0040:T1499.002,TA0001:T1190" # Impact:Service Exhaustion Flood, Initial Access:Exploit Public-Facing Application }) } -query "apache_error_rate_by_endpoint" { +query "apache_endpoint_high_error_rate_detected" { sql = <<-EOQ select request_uri as endpoint, @@ -243,20 +243,20 @@ EOQ } -detection "apache_client_error_analysis" { - title = "Client Error Analysis" - description = "Analyze patterns in client-side errors (4xx) to identify potential client issues." +detection "apache_client_error_pattern_detected" { + title = "Apache Client Error Pattern Detected" + description = "Detect when an Apache web server logged patterns in client-side errors (4xx) to check for potential client issues, invalid requests, or reconnaissance activities." severity = "medium" display_columns = ["status_code", "error_count", "percentage", "top_uri", "uri_count"] - query = query.apache_client_error_analysis + query = query.apache_client_error_pattern_detected tags = merge(local.apache_operational_common_tags, { mitre_attack_id = "TA0001:T1190,TA0043:T1595" # Initial Access:Exploit Public-Facing Application, Reconnaissance:Active Scanning }) } -query "apache_client_error_analysis" { +query "apache_client_error_pattern_detected" { sql = <<-EOQ with client_errors as ( select @@ -303,20 +303,20 @@ EOQ } -detection "apache_server_error_analysis" { - title = "Server Error Analysis" - description = "Analyze patterns in server-side errors (5xx) to identify potential server issues." +detection "apache_server_error_pattern_detected" { + title = "Apache Server Error Pattern Detected" + description = "Detect when an Apache web server logged patterns in server-side errors (5xx) to check for potential server issues, application failures, or infrastructure problems." severity = "high" display_columns = ["status_code", "error_count", "percentage", "top_uri", "uri_count"] - query = query.apache_server_error_analysis + query = query.apache_server_error_pattern_detected tags = merge(local.apache_operational_common_tags, { mitre_attack_id = "TA0040:T1499.004,TA0040:T1499.003" # Impact:Application or System Exploitation, Impact:Application Exhaustion Flood }) } -query "apache_server_error_analysis" { +query "apache_server_error_pattern_detected" { sql = <<-EOQ with server_errors as ( select diff --git a/detections/apache_performance.pp b/detections/apache_performance.pp index 369979f..908471a 100644 --- a/detections/apache_performance.pp +++ b/detections/apache_performance.pp @@ -9,13 +9,13 @@ description = "This benchmark contains performance-focused detections when scanning Apache access logs." type = "detection" children = [ - detection.apache_very_slow_requests, - detection.apache_large_static_file_requests, - detection.apache_timeout_errors, - detection.apache_slow_response_time, - detection.apache_response_time_anomalies, - detection.apache_high_traffic_endpoints, - detection.apache_connection_pool_exhaustion + detection.apache_very_slow_request_detected, + detection.apache_large_static_file_requested, + detection.apache_request_timeout_occurred, + detection.apache_slow_response_time_detected, + detection.apache_response_time_anomaly_detected, + detection.apache_high_traffic_endpoint_detected, + detection.apache_connection_pool_exhaustion_risk_detected ] tags = merge(local.apache_performance_common_tags, { @@ -23,20 +23,20 @@ }) } -detection "apache_very_slow_requests" { - title = "Very Slow HTTP Requests" - description = "Detect individual HTTP requests with abnormally high response times." +detection "apache_very_slow_request_detected" { + title = "Apache Very Slow Request Detected" + description = "Detect when an Apache web server processed HTTP requests with abnormally high response times to check for performance bottlenecks, resource contention, or potential DoS conditions." severity = "high" display_columns = ["request_ip", "request_path", "request_method", "response_time", "status_code", "timestamp"] - query = query.apache_very_slow_requests + query = query.apache_very_slow_request_detected tags = merge(local.apache_performance_common_tags, { mitre_attack_id = "TA0040:T1499.003" # Impact:Application Exhaustion Flood }) } -query "apache_very_slow_requests" { +query "apache_very_slow_request_detected" { sql = <<-EOQ select remote_addr as request_ip, @@ -54,20 +54,20 @@ EOQ } -detection "apache_large_static_file_requests" { - title = "Large Static File Requests" - description = "Detect requests for large static files that could impact server performance." +detection "apache_large_static_file_requested" { + title = "Apache Large Static File Requested" + description = "Detect when an Apache web server processed requests for large static files to check for potential bandwidth consumption, server load issues, or content delivery optimization opportunities." severity = "medium" display_columns = ["request_ip", "request_path", "file_type", "body_bytes", "status_code", "timestamp"] - query = query.apache_large_static_file_requests + query = query.apache_large_static_file_requested tags = merge(local.apache_performance_common_tags, { mitre_attack_id = "TA0040:T1499.002" # Impact:Service Exhaustion Flood }) } -query "apache_large_static_file_requests" { +query "apache_large_static_file_requested" { sql = <<-EOQ select remote_addr as request_ip, @@ -109,20 +109,20 @@ EOQ } -detection "apache_timeout_errors" { - title = "Request Timeout Errors" - description = "Detect HTTP 408 Request Timeout or 504 Gateway Timeout errors indicating resource constraints." +detection "apache_request_timeout_occurred" { + title = "Apache Request Timeout Occurred" + description = "Detect when an Apache web server returned HTTP 408 Request Timeout or 504 Gateway Timeout errors to check for resource constraints, server overload, or slow upstream services." severity = "high" display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] - query = query.apache_timeout_errors + query = query.apache_request_timeout_occurred tags = merge(local.apache_performance_common_tags, { mitre_attack_id = "TA0040:T1499.004" # Impact:Application or System Exploitation }) } -query "apache_timeout_errors" { +query "apache_request_timeout_occurred" { sql = <<-EOQ select remote_addr as request_ip, @@ -139,20 +139,20 @@ EOQ } -detection "apache_slow_response_time" { - title = "Slow Response Time Detected" - description = "Detect endpoints with consistently high response times exceeding threshold." +detection "apache_slow_response_time_detected" { + title = "Apache Slow Response Time Detected" + description = "Detect when an Apache web server processed requests to endpoints with consistently high response times to check for performance bottlenecks, inefficient code paths, or database query issues." severity = "high" display_columns = ["endpoint", "avg_response_time", "request_count", "max_response_time"] - query = query.apache_slow_response_time + query = query.apache_slow_response_time_detected tags = merge(local.apache_performance_common_tags, { mitre_attack_id = "TA0040:T1499.003,TA0040:T1496.001" # Impact:Application Exhaustion Flood, Impact:Compute Hijacking }) } -query "apache_slow_response_time" { +query "apache_slow_response_time_detected" { sql = <<-EOQ with response_stats as ( select @@ -185,20 +185,20 @@ EOQ } -detection "apache_response_time_anomalies" { - title = "Response Time Anomalies Detected" - description = "Detect sudden increases in response time compared to historical patterns." +detection "apache_response_time_anomaly_detected" { + title = "Apache Response Time Anomaly Detected" + description = "Detect when an Apache web server experienced sudden increases in response time compared to historical patterns to check for performance degradation, service disruptions, or infrastructure changes." severity = "high" display_columns = ["window_start", "window_end", "avg_response_time", "historical_avg", "deviation_percent"] - query = query.apache_response_time_anomalies + query = query.apache_response_time_anomaly_detected tags = merge(local.apache_performance_common_tags, { mitre_attack_id = "TA0040:T1499.003,TA0040:T1496.001" # Impact:Application Exhaustion Flood, Impact:Compute Hijacking }) } -query "apache_response_time_anomalies" { +query "apache_response_time_anomaly_detected" { sql = <<-EOQ with time_windows as ( select @@ -232,20 +232,20 @@ EOQ } -detection "apache_high_traffic_endpoints" { - title = "High Traffic Endpoints" - description = "Identify endpoints receiving unusually high traffic volumes." +detection "apache_high_traffic_endpoint_detected" { + title = "Apache High Traffic Endpoint Detected" + description = "Detect when an Apache web server handled unusually high traffic volumes to specific endpoints to check for resource consumption patterns, hot spots in the application, or potential areas for optimization." severity = "medium" display_columns = ["endpoint", "request_count", "traffic_percent", "avg_response_time"] - query = query.apache_high_traffic_endpoints + query = query.apache_high_traffic_endpoint_detected tags = merge(local.apache_performance_common_tags, { mitre_attack_id = "TA0040:T1499.002,TA0040:T1498.001" # Impact:Service Exhaustion Flood, Impact:Direct Network Flood }) } -query "apache_high_traffic_endpoints" { +query "apache_high_traffic_endpoint_detected" { sql = <<-EOQ with endpoint_traffic as ( select @@ -281,20 +281,20 @@ EOQ } -detection "apache_connection_pool_exhaustion" { - title = "Connection Pool Exhaustion Risk" - description = "Detect risk of connection pool exhaustion based on concurrent connections." +detection "apache_connection_pool_exhaustion_risk_detected" { + title = "Apache Connection Pool Exhaustion Risk Detected" + description = "Detect when an Apache web server showed signs of connection pool exhaustion based on concurrent connections to check for capacity limits, resource constraints, or potential denial of service conditions." severity = "critical" display_columns = ["timestamp", "concurrent_connections", "rejection_rate"] - query = query.apache_connection_pool_exhaustion + query = query.apache_connection_pool_exhaustion_risk_detected tags = merge(local.apache_performance_common_tags, { mitre_attack_id = "TA0040:T1499.002" # Impact:Service Exhaustion Flood }) } -query "apache_connection_pool_exhaustion" { +query "apache_connection_pool_exhaustion_risk_detected" { sql = <<-EOQ with connection_stats as ( select diff --git a/detections/apache_security.pp b/detections/apache_security.pp index e1f3e68..377be6d 100644 --- a/detections/apache_security.pp +++ b/detections/apache_security.pp @@ -9,15 +9,15 @@ description = "This benchmark contains security-focused detections when scanning Apache access logs." type = "detection" children = [ - detection.apache_sql_injection_attempts, - detection.apache_directory_traversal_attempts, - detection.apache_brute_force_auth_attempts, - detection.apache_suspicious_user_agents, - detection.apache_xss_attempts, - detection.apache_sensitive_file_access, - detection.apache_unusual_http_methods, - detection.apache_web_shell_detection, - detection.apache_api_key_exposure + detection.apache_sql_injection_attempted, + detection.apache_directory_traversal_attempted, + detection.apache_brute_force_auth_attempted, + detection.apache_suspicious_user_agent_detected, + detection.apache_xss_attempted, + detection.apache_sensitive_file_access_attempted, + detection.apache_unusual_http_method_used, + detection.apache_web_shell_access_attempted, + detection.apache_api_key_exposed ] tags = merge(local.apache_security_common_tags, { @@ -25,20 +25,20 @@ }) } -detection "apache_sql_injection_attempts" { - title = "SQL Injection Attempts Detected" - description = "Detect potential SQL injection attempts in URL parameters and request paths." +detection "apache_sql_injection_attempted" { + title = "Apache SQL Injection Attempted" + description = "Detect when an Apache web server was targeted by SQL injection attempts to check for potential database compromise, data theft, or unauthorized system access." severity = "critical" display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] - query = query.apache_sql_injection_attempts + query = query.apache_sql_injection_attempted tags = merge(local.apache_security_common_tags, { mitre_attack_ids = "TA0009:T1190" }) } -query "apache_sql_injection_attempts" { +query "apache_sql_injection_attempted" { sql = <<-EOQ select remote_addr as request_ip, @@ -65,20 +65,20 @@ EOQ } -detection "apache_directory_traversal_attempts" { - title = "Directory Traversal Attempts Detected" - description = "Detect attempts to traverse directories using ../ patterns in URLs." +detection "apache_directory_traversal_attempted" { + title = "Apache Directory Traversal Attempted" + description = "Detect when an Apache web server was targeted by directory traversal attempts to check for unauthorized access to sensitive files outside the web root directory." severity = "high" display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] - query = query.apache_directory_traversal_attempts + query = query.apache_directory_traversal_attempted tags = merge(local.apache_security_common_tags, { mitre_attack_ids = "TA0009:T1083" }) } -query "apache_directory_traversal_attempts" { +query "apache_directory_traversal_attempted" { sql = <<-EOQ select remote_addr as request_ip, @@ -106,20 +106,20 @@ EOQ } -detection "apache_brute_force_auth_attempts" { - title = "Brute Force Authentication Attempts Detected" - description = "Detect potential brute force authentication attempts." +detection "apache_brute_force_auth_attempted" { + title = "Apache Brute Force Authentication Attempted" + description = "Detect when an Apache web server was targeted by brute force authentication attempts to check for potential credential compromise and unauthorized access." severity = "high" display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] - query = query.apache_brute_force_auth_attempts + query = query.apache_brute_force_auth_attempted tags = merge(local.apache_security_common_tags, { mitre_attack_ids = "TA0009:T1110" }) } -query "apache_brute_force_auth_attempts" { +query "apache_brute_force_auth_attempted" { sql = <<-EOQ select remote_addr as request_ip, @@ -157,20 +157,20 @@ EOQ } -detection "apache_suspicious_user_agents" { - title = "Suspicious User Agents Detected" - description = "Detect requests from known malicious or suspicious user agents." +detection "apache_suspicious_user_agent_detected" { + title = "Apache Suspicious User Agent Detected" + description = "Detect when an Apache web server received requests with known malicious user agents to check for reconnaissance activities and potential targeted attacks." severity = "medium" display_columns = ["request_ip", "user_agent", "request_path", "status_code", "timestamp"] - query = query.apache_suspicious_user_agents + query = query.apache_suspicious_user_agent_detected tags = merge(local.apache_security_common_tags, { mitre_attack_ids = "TA0043:T1592" }) } -query "apache_suspicious_user_agents" { +query "apache_suspicious_user_agent_detected" { sql = <<-EOQ select remote_addr as request_ip, @@ -200,20 +200,20 @@ EOQ } -detection "apache_xss_attempts" { - title = "Cross-Site Scripting (XSS) Attempts" - description = "Detect potential XSS attacks in request parameters and paths." +detection "apache_xss_attempted" { + title = "Apache Cross-Site Scripting Attempted" + description = "Detect when an Apache web server was targeted by cross-site scripting (XSS) attacks to check for potential client-side code injection that could lead to session hijacking or credential theft." severity = "critical" display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] - query = query.apache_xss_attempts + query = query.apache_xss_attempted tags = merge(local.apache_security_common_tags, { mitre_attack_ids = "TA0009:T1059.007" }) } -query "apache_xss_attempts" { +query "apache_xss_attempted" { sql = <<-EOQ select remote_addr as request_ip, @@ -243,20 +243,20 @@ EOQ } -detection "apache_sensitive_file_access" { - title = "Sensitive File Access Attempts" - description = "Detect attempts to access sensitive files or directories." +detection "apache_sensitive_file_access_attempted" { + title = "Apache Sensitive File Access Attempted" + description = "Detect when an Apache web server received requests for sensitive files or directories to check for potential information disclosure, configuration leaks, or access to restricted resources." severity = "high" display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] - query = query.apache_sensitive_file_access + query = query.apache_sensitive_file_access_attempted tags = merge(local.apache_security_common_tags, { mitre_attack_ids = "TA0009:T1083" }) } -query "apache_sensitive_file_access" { +query "apache_sensitive_file_access_attempted" { sql = <<-EOQ select remote_addr as request_ip, @@ -295,20 +295,20 @@ EOQ } -detection "apache_unusual_http_methods" { - title = "Unusual HTTP Methods Detected" - description = "Detect requests using unusual or potentially dangerous HTTP methods." +detection "apache_unusual_http_method_used" { + title = "Apache Unusual HTTP Method Used" + description = "Detect when an Apache web server received requests using unusual or potentially dangerous HTTP methods to check for exploitation attempts, information disclosure, or unauthorized modifications." severity = "medium" display_columns = ["request_ip", "request_method", "request_path", "status_code", "timestamp"] - query = query.apache_unusual_http_methods + query = query.apache_unusual_http_method_used tags = merge(local.apache_security_common_tags, { mitre_attack_ids = "TA0009:T1213" }) } -query "apache_unusual_http_methods" { +query "apache_unusual_http_method_used" { sql = <<-EOQ select remote_addr as request_ip, @@ -334,20 +334,20 @@ EOQ } -detection "apache_web_shell_detection" { - title = "Web Shell Upload or Access Attempts" - description = "Detect potential web shell uploads or access attempts." +detection "apache_web_shell_access_attempted" { + title = "Apache Web Shell Access Attempted" + description = "Detect when an Apache web server received potential web shell upload or access attempts to check for backdoor installation, persistent access, or remote code execution." severity = "critical" display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] - query = query.apache_web_shell_detection + query = query.apache_web_shell_access_attempted tags = merge(local.apache_security_common_tags, { mitre_attack_ids = "TA0003:T1505.003" }) } -query "apache_web_shell_detection" { +query "apache_web_shell_access_attempted" { sql = <<-EOQ select remote_addr as request_ip, @@ -389,20 +389,20 @@ EOQ } -detection "apache_api_key_exposure" { - title = "API Key or Token Exposure" - description = "Detect potential exposure of API keys or tokens in URLs." +detection "apache_api_key_exposed" { + title = "Apache API Key Exposed" + description = "Detect when an Apache web server logged potential API keys or tokens in URLs to check for credential exposure, which could lead to unauthorized access to external services or systems." severity = "critical" display_columns = ["request_ip", "request_path", "token_type", "status_code", "timestamp"] - query = query.apache_api_key_exposure + query = query.apache_api_key_exposed tags = merge(local.apache_security_common_tags, { mitre_attack_ids = "TA0006:T1552" }) } -query "apache_api_key_exposure" { +query "apache_api_key_exposed" { sql = <<-EOQ select remote_addr as request_ip, From 457c890053226a40c907e246cf4641b1da83b8ca Mon Sep 17 00:00:00 2001 From: Priyanka Chatterjee Date: Fri, 4 Apr 2025 18:39:28 +0530 Subject: [PATCH 06/62] Add local detection_display_columns --- dashboards/activity_dashboard.pp | 4 ++-- detections/apache_compliance.pp | 8 ++++---- detections/apache_operational.pp | 16 ++++++++-------- detections/apache_performance.pp | 14 +++++++------- detections/apache_security.pp | 18 +++++++++--------- locals.pp | 25 +++++++++++++++++++++++++ 6 files changed, 55 insertions(+), 30 deletions(-) diff --git a/dashboards/activity_dashboard.pp b/dashboards/activity_dashboard.pp index 129c0cf..dd82c5b 100644 --- a/dashboards/activity_dashboard.pp +++ b/dashboards/activity_dashboard.pp @@ -1,6 +1,6 @@ -dashboard "apache_activity_dashboard" { +dashboard "activity_dashboard" { title = "Apache Log Activity Dashboard" - documentation = file("./dashboards/docs/apache_activity_dashboard.md") + documentation = file("./dashboards/docs/activity_dashboard.md") tags = { type = "Dashboard" diff --git a/detections/apache_compliance.pp b/detections/apache_compliance.pp index fd34b60..37b232c 100644 --- a/detections/apache_compliance.pp +++ b/detections/apache_compliance.pp @@ -24,7 +24,7 @@ title = "Apache PII Data Exposed In URL" description = "Detect when an Apache web server logged Personally Identifiable Information (PII) in URLs to check for potential data privacy violations, regulatory non-compliance, and sensitive information disclosure." severity = "critical" - display_columns = ["request_ip", "request_path", "pii_type", "status_code", "timestamp"] + display_columns = local.detection_display_columns query = query.apache_pii_data_exposed_in_url @@ -73,7 +73,7 @@ title = "Apache Restricted Resource Accessed" description = "Detect when an Apache web server processed requests to restricted resources or administrative areas to check for unauthorized access attempts, privilege escalation, or security policy violations." severity = "high" - display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] + display_columns = local.detection_display_columns query = query.apache_restricted_resource_accessed @@ -120,7 +120,7 @@ title = "Apache Unauthorized IP Access Detected" description = "Detect when an Apache web server received requests from unauthorized IP ranges or geographic locations to check for potential security policy violations, access control bypasses, or geofencing compliance issues." severity = "high" - display_columns = ["request_ip", "request_count", "first_access", "last_access"] + display_columns = local.detection_display_columns query = query.apache_unauthorized_ip_access_detected @@ -160,7 +160,7 @@ title = "Apache Data Privacy Requirement Violated" description = "Detect when an Apache web server processed requests that potentially violate data privacy requirements to check for regulatory compliance issues, sensitive data handling violations, or privacy policy infractions." severity = "high" - display_columns = ["endpoint", "total_requests", "sensitive_data_count", "unique_ips"] + display_columns = local.detection_display_columns query = query.apache_data_privacy_requirement_violated diff --git a/detections/apache_operational.pp b/detections/apache_operational.pp index a23e30b..7dbae53 100644 --- a/detections/apache_operational.pp +++ b/detections/apache_operational.pp @@ -28,7 +28,7 @@ title = "Apache Internal Server Error Occurred" description = "Detect when an Apache web server returned HTTP 500 Internal Server Error responses to check for server-side failures, application crashes, or misconfiguration issues." severity = "high" - display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] + display_columns = local.detection_display_columns query = query.apache_internal_server_error_occurred @@ -58,7 +58,7 @@ title = "Apache Missing User Agent Detected" description = "Detect when an Apache web server received requests with missing user agent headers to check for potential automated tools, scripted attacks, or non-standard clients." severity = "medium" - display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] + display_columns = local.detection_display_columns query = query.apache_missing_user_agent_detected @@ -90,7 +90,7 @@ title = "Apache Large Payload Request Detected" description = "Detect when an Apache web server processed requests with unusually large body sizes to check for potential file uploads, data exfiltration attempts, or resource consumption issues." severity = "medium" - display_columns = ["request_ip", "request_path", "request_method", "body_bytes", "status_code", "timestamp"] + display_columns = local.detection_display_columns query = query.apache_large_payload_request_detected @@ -121,7 +121,7 @@ title = "Apache High Error Rate Detected" description = "Detect when an Apache web server experienced a high rate of HTTP errors within a time window to check for potential service disruptions, application failures, or attack patterns." severity = "high" - display_columns = ["error_count", "total_requests", "error_rate", "window_start", "window_end"] + display_columns = local.detection_display_columns query = query.apache_high_error_rate_detected @@ -166,7 +166,7 @@ title = "Apache Unusual Traffic Spike Detected" description = "Detect when an Apache web server experienced unusual spikes in traffic volume compared to historical patterns to check for potential DDoS attacks, viral content, or unexpected application behavior." severity = "medium" - display_columns = ["request_count", "avg_historical_requests", "deviation_percent", "window_start", "window_end"] + display_columns = local.detection_display_columns query = query.apache_unusual_traffic_spike_detected @@ -211,7 +211,7 @@ title = "Apache Endpoint High Error Rate Detected" description = "Detect when an Apache web server processed requests to specific endpoints with unusually high error rates to check for broken functionality, misconfiguration, or targeted attacks against specific application components." severity = "high" - display_columns = ["endpoint", "error_count", "total_requests", "error_rate"] + display_columns = local.detection_display_columns query = query.apache_endpoint_high_error_rate_detected @@ -247,7 +247,7 @@ title = "Apache Client Error Pattern Detected" description = "Detect when an Apache web server logged patterns in client-side errors (4xx) to check for potential client issues, invalid requests, or reconnaissance activities." severity = "medium" - display_columns = ["status_code", "error_count", "percentage", "top_uri", "uri_count"] + display_columns = local.detection_display_columns query = query.apache_client_error_pattern_detected @@ -307,7 +307,7 @@ title = "Apache Server Error Pattern Detected" description = "Detect when an Apache web server logged patterns in server-side errors (5xx) to check for potential server issues, application failures, or infrastructure problems." severity = "high" - display_columns = ["status_code", "error_count", "percentage", "top_uri", "uri_count"] + display_columns = local.detection_display_columns query = query.apache_server_error_pattern_detected diff --git a/detections/apache_performance.pp b/detections/apache_performance.pp index 908471a..b58c1a2 100644 --- a/detections/apache_performance.pp +++ b/detections/apache_performance.pp @@ -27,7 +27,7 @@ title = "Apache Very Slow Request Detected" description = "Detect when an Apache web server processed HTTP requests with abnormally high response times to check for performance bottlenecks, resource contention, or potential DoS conditions." severity = "high" - display_columns = ["request_ip", "request_path", "request_method", "response_time", "status_code", "timestamp"] + display_columns = local.detection_display_columns query = query.apache_very_slow_request_detected @@ -58,7 +58,7 @@ title = "Apache Large Static File Requested" description = "Detect when an Apache web server processed requests for large static files to check for potential bandwidth consumption, server load issues, or content delivery optimization opportunities." severity = "medium" - display_columns = ["request_ip", "request_path", "file_type", "body_bytes", "status_code", "timestamp"] + display_columns = local.detection_display_columns query = query.apache_large_static_file_requested @@ -113,7 +113,7 @@ title = "Apache Request Timeout Occurred" description = "Detect when an Apache web server returned HTTP 408 Request Timeout or 504 Gateway Timeout errors to check for resource constraints, server overload, or slow upstream services." severity = "high" - display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] + display_columns = local.detection_display_columns query = query.apache_request_timeout_occurred @@ -143,7 +143,7 @@ title = "Apache Slow Response Time Detected" description = "Detect when an Apache web server processed requests to endpoints with consistently high response times to check for performance bottlenecks, inefficient code paths, or database query issues." severity = "high" - display_columns = ["endpoint", "avg_response_time", "request_count", "max_response_time"] + display_columns = local.detection_display_columns query = query.apache_slow_response_time_detected @@ -189,7 +189,7 @@ title = "Apache Response Time Anomaly Detected" description = "Detect when an Apache web server experienced sudden increases in response time compared to historical patterns to check for performance degradation, service disruptions, or infrastructure changes." severity = "high" - display_columns = ["window_start", "window_end", "avg_response_time", "historical_avg", "deviation_percent"] + display_columns = local.detection_display_columns query = query.apache_response_time_anomaly_detected @@ -236,7 +236,7 @@ title = "Apache High Traffic Endpoint Detected" description = "Detect when an Apache web server handled unusually high traffic volumes to specific endpoints to check for resource consumption patterns, hot spots in the application, or potential areas for optimization." severity = "medium" - display_columns = ["endpoint", "request_count", "traffic_percent", "avg_response_time"] + display_columns = local.detection_display_columns query = query.apache_high_traffic_endpoint_detected @@ -285,7 +285,7 @@ title = "Apache Connection Pool Exhaustion Risk Detected" description = "Detect when an Apache web server showed signs of connection pool exhaustion based on concurrent connections to check for capacity limits, resource constraints, or potential denial of service conditions." severity = "critical" - display_columns = ["timestamp", "concurrent_connections", "rejection_rate"] + display_columns = local.detection_display_columns query = query.apache_connection_pool_exhaustion_risk_detected diff --git a/detections/apache_security.pp b/detections/apache_security.pp index 377be6d..3ac69aa 100644 --- a/detections/apache_security.pp +++ b/detections/apache_security.pp @@ -29,7 +29,7 @@ title = "Apache SQL Injection Attempted" description = "Detect when an Apache web server was targeted by SQL injection attempts to check for potential database compromise, data theft, or unauthorized system access." severity = "critical" - display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] + display_columns = local.detection_display_columns query = query.apache_sql_injection_attempted @@ -69,7 +69,7 @@ title = "Apache Directory Traversal Attempted" description = "Detect when an Apache web server was targeted by directory traversal attempts to check for unauthorized access to sensitive files outside the web root directory." severity = "high" - display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] + display_columns = local.detection_display_columns query = query.apache_directory_traversal_attempted @@ -110,7 +110,7 @@ title = "Apache Brute Force Authentication Attempted" description = "Detect when an Apache web server was targeted by brute force authentication attempts to check for potential credential compromise and unauthorized access." severity = "high" - display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] + display_columns = local.detection_display_columns query = query.apache_brute_force_auth_attempted @@ -161,7 +161,7 @@ title = "Apache Suspicious User Agent Detected" description = "Detect when an Apache web server received requests with known malicious user agents to check for reconnaissance activities and potential targeted attacks." severity = "medium" - display_columns = ["request_ip", "user_agent", "request_path", "status_code", "timestamp"] + display_columns = local.detection_display_columns query = query.apache_suspicious_user_agent_detected @@ -204,7 +204,7 @@ title = "Apache Cross-Site Scripting Attempted" description = "Detect when an Apache web server was targeted by cross-site scripting (XSS) attacks to check for potential client-side code injection that could lead to session hijacking or credential theft." severity = "critical" - display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] + display_columns = local.detection_display_columns query = query.apache_xss_attempted @@ -247,7 +247,7 @@ title = "Apache Sensitive File Access Attempted" description = "Detect when an Apache web server received requests for sensitive files or directories to check for potential information disclosure, configuration leaks, or access to restricted resources." severity = "high" - display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] + display_columns = local.detection_display_columns query = query.apache_sensitive_file_access_attempted @@ -299,7 +299,7 @@ title = "Apache Unusual HTTP Method Used" description = "Detect when an Apache web server received requests using unusual or potentially dangerous HTTP methods to check for exploitation attempts, information disclosure, or unauthorized modifications." severity = "medium" - display_columns = ["request_ip", "request_method", "request_path", "status_code", "timestamp"] + display_columns = local.detection_display_columns query = query.apache_unusual_http_method_used @@ -338,7 +338,7 @@ title = "Apache Web Shell Access Attempted" description = "Detect when an Apache web server received potential web shell upload or access attempts to check for backdoor installation, persistent access, or remote code execution." severity = "critical" - display_columns = ["request_ip", "request_path", "request_method", "status_code", "timestamp"] + display_columns = local.detection_display_columns query = query.apache_web_shell_access_attempted @@ -393,7 +393,7 @@ title = "Apache API Key Exposed" description = "Detect when an Apache web server logged potential API keys or tokens in URLs to check for credential exposure, which could lead to unauthorized access to external services or systems." severity = "critical" - display_columns = ["request_ip", "request_path", "token_type", "status_code", "timestamp"] + display_columns = local.detection_display_columns query = query.apache_api_key_exposed diff --git a/locals.pp b/locals.pp index c2daa3f..237338d 100644 --- a/locals.pp +++ b/locals.pp @@ -6,3 +6,28 @@ } } +locals { + # Local internal variables to build the SQL select clause for common + # dimensions. Do not edit directly. + detection_sql_columns = <<-EOQ + tp_timestamp as timestamp, + request_method || ' ' || request_uri as operation, + tp_source_ip as source_ip, + server_name as server, + tp_id as detection_id, + * + EOQ +} + +locals { + # Local internal variables to build the SQL select clause for common + # dimensions. Do not edit directly. + detection_display_columns = [ + "timestamp", + "request_method", + "request_uri", + "tp_source_ip", + "status", + "server_name", + ] +} \ No newline at end of file From efa02127a51922af82e7c9148ed81041727fde04 Mon Sep 17 00:00:00 2001 From: Priyanka Chatterjee Date: Fri, 4 Apr 2025 19:29:22 +0530 Subject: [PATCH 07/62] Refactor naming conventions for benchmarks and detections --- detections/apache_access_logs.pp | 14 ++-- detections/apache_compliance.pp | 66 +++++++-------- detections/apache_operational.pp | 122 +++++++++++++-------------- detections/apache_performance.pp | 108 ++++++++++++------------ detections/apache_security.pp | 140 ++++++++++++++++--------------- 5 files changed, 227 insertions(+), 223 deletions(-) diff --git a/detections/apache_access_logs.pp b/detections/apache_access_logs.pp index e09de08..3c65e45 100644 --- a/detections/apache_access_logs.pp +++ b/detections/apache_access_logs.pp @@ -1,12 +1,12 @@ -benchmark "apache_access_log_detections" { - title = "Apache Access Log Detections" - description = "This benchmark contains recommendations when scanning Apache access logs." +benchmark "access_log_detections" { + title = "Access Log Detections" + description = "This benchmark contains recommendations when scanning access logs." type = "detection" children = [ - benchmark.apache_security_detections, - benchmark.apache_operational_detections, - benchmark.apache_performance_detections, - benchmark.apache_compliance_detections + benchmark.security_detections, + benchmark.operational_detections, + benchmark.performance_detections, + benchmark.compliance_detections ] tags = merge(local.apache_access_log_detections_common_tags, { diff --git a/detections/apache_compliance.pp b/detections/apache_compliance.pp index 37b232c..b2210d1 100644 --- a/detections/apache_compliance.pp +++ b/detections/apache_compliance.pp @@ -1,39 +1,39 @@ locals { - apache_compliance_common_tags = merge(local.apache_access_log_detections_common_tags, { + compliance_common_tags = merge(local.apache_access_log_detections_common_tags, { category = "Compliance" }) } -benchmark "apache_compliance_detections" { - title = "Apache Compliance Detections" - description = "This benchmark contains compliance-focused detections when scanning Apache access logs." +benchmark "compliance_detections" { + title = "Compliance Detections" + description = "This benchmark contains compliance-focused detections when scanning access logs." type = "detection" children = [ - detection.apache_pii_data_exposed_in_url, - detection.apache_restricted_resource_accessed, - detection.apache_unauthorized_ip_access_detected, - detection.apache_data_privacy_requirement_violated + detection.pii_data_exposed_in_url, + detection.restricted_resource_accessed, + detection.unauthorized_ip_access_detected, + detection.data_privacy_requirement_violated ] - tags = merge(local.apache_compliance_common_tags, { + tags = merge(local.compliance_common_tags, { type = "Benchmark" }) } -detection "apache_pii_data_exposed_in_url" { - title = "Apache PII Data Exposed In URL" - description = "Detect when an Apache web server logged Personally Identifiable Information (PII) in URLs to check for potential data privacy violations, regulatory non-compliance, and sensitive information disclosure." +detection "pii_data_exposed_in_url" { + title = "PII Data Exposed In URL" + description = "Detect when a web server logged Personally Identifiable Information (PII) in URLs to check for potential data privacy violations, regulatory non-compliance, and sensitive information disclosure." severity = "critical" display_columns = local.detection_display_columns - query = query.apache_pii_data_exposed_in_url + query = query.pii_data_exposed_in_url - tags = merge(local.apache_compliance_common_tags, { + tags = merge(local.compliance_common_tags, { mitre_attack_id = "TA0006:T1552.001" # Credential Access:Credentials In Files }) } -query "apache_pii_data_exposed_in_url" { +query "pii_data_exposed_in_url" { sql = <<-EOQ with pii_patterns as ( select @@ -69,20 +69,20 @@ EOQ } -detection "apache_restricted_resource_accessed" { - title = "Apache Restricted Resource Accessed" - description = "Detect when an Apache web server processed requests to restricted resources or administrative areas to check for unauthorized access attempts, privilege escalation, or security policy violations." +detection "restricted_resource_accessed" { + title = "Restricted Resource Accessed" + description = "Detect when a web server processed requests to restricted resources or administrative areas to check for unauthorized access attempts, privilege escalation, or security policy violations." severity = "high" display_columns = local.detection_display_columns - query = query.apache_restricted_resource_accessed + query = query.restricted_resource_accessed - tags = merge(local.apache_compliance_common_tags, { + tags = merge(local.compliance_common_tags, { mitre_attack_id = "TA0001:T1190,TA0008:T1133" # Initial Access:Exploit Public-Facing Application, Lateral Movement:External Remote Services }) } -query "apache_restricted_resource_accessed" { +query "restricted_resource_accessed" { sql = <<-EOQ select remote_addr as request_ip, @@ -116,20 +116,20 @@ EOQ } -detection "apache_unauthorized_ip_access_detected" { - title = "Apache Unauthorized IP Access Detected" - description = "Detect when an Apache web server received requests from unauthorized IP ranges or geographic locations to check for potential security policy violations, access control bypasses, or geofencing compliance issues." +detection "unauthorized_ip_access_detected" { + title = "Unauthorized IP Access Detected" + description = "Detect when a web server received requests from unauthorized IP ranges or geographic locations to check for potential security policy violations, access control bypasses, or geofencing compliance issues." severity = "high" display_columns = local.detection_display_columns - query = query.apache_unauthorized_ip_access_detected + query = query.unauthorized_ip_access_detected - tags = merge(local.apache_compliance_common_tags, { + tags = merge(local.compliance_common_tags, { mitre_attack_id = "TA0008:T1133,TA0003:T1078.004" # Lateral Movement:External Remote Services, Persistence:Cloud Accounts }) } -query "apache_unauthorized_ip_access_detected" { +query "unauthorized_ip_access_detected" { sql = <<-EOQ with unauthorized_access as ( select @@ -156,20 +156,20 @@ EOQ } -detection "apache_data_privacy_requirement_violated" { - title = "Apache Data Privacy Requirement Violated" - description = "Detect when an Apache web server processed requests that potentially violate data privacy requirements to check for regulatory compliance issues, sensitive data handling violations, or privacy policy infractions." +detection "data_privacy_requirement_violated" { + title = "Data Privacy Requirement Violated" + description = "Detect when a web server processed requests that potentially violate data privacy requirements to check for regulatory compliance issues, sensitive data handling violations, or privacy policy infractions." severity = "high" display_columns = local.detection_display_columns - query = query.apache_data_privacy_requirement_violated + query = query.data_privacy_requirement_violated - tags = merge(local.apache_compliance_common_tags, { + tags = merge(local.compliance_common_tags, { mitre_attack_id = "TA0009:T1530,TA0006:T1552.001" # Collection:Data from Cloud Storage, Credential Access:Credentials In Files }) } -query "apache_data_privacy_requirement_violated" { +query "data_privacy_requirement_violated" { sql = <<-EOQ with privacy_endpoints as ( select diff --git a/detections/apache_operational.pp b/detections/apache_operational.pp index 7dbae53..54d7821 100644 --- a/detections/apache_operational.pp +++ b/detections/apache_operational.pp @@ -1,43 +1,43 @@ locals { - apache_operational_common_tags = merge(local.apache_access_log_detections_common_tags, { + operational_common_tags = merge(local.apache_access_log_detections_common_tags, { category = "Operational" }) } -benchmark "apache_operational_detections" { - title = "Apache Operational Detections" - description = "This benchmark contains operational detections when scanning Apache access logs." +benchmark "operational_detections" { + title = "Operational Detections" + description = "This benchmark contains operational detections when scanning access logs." type = "detection" children = [ - detection.apache_internal_server_error_occurred, - detection.apache_missing_user_agent_detected, - detection.apache_large_payload_request_detected, - detection.apache_high_error_rate_detected, - detection.apache_unusual_traffic_spike_detected, - detection.apache_endpoint_high_error_rate_detected, - detection.apache_client_error_pattern_detected, - detection.apache_server_error_pattern_detected + detection.internal_server_error_occurred, + detection.missing_user_agent_detected, + detection.large_payload_request_detected, + detection.high_error_rate_detected, + detection.unusual_traffic_spike_detected, + detection.endpoint_high_error_rate_detected, + detection.client_error_pattern_detected, + detection.server_error_pattern_detected ] - tags = merge(local.apache_operational_common_tags, { + tags = merge(local.operational_common_tags, { type = "Benchmark" }) } -detection "apache_internal_server_error_occurred" { - title = "Apache Internal Server Error Occurred" - description = "Detect when an Apache web server returned HTTP 500 Internal Server Error responses to check for server-side failures, application crashes, or misconfiguration issues." +detection "internal_server_error_occurred" { + title = "Internal Server Error Occurred" + description = "Detect when a web server returned HTTP 500 Internal Server Error responses to check for server-side failures, application crashes, or misconfiguration issues." severity = "high" display_columns = local.detection_display_columns - query = query.apache_internal_server_error_occurred + query = query.internal_server_error_occurred - tags = merge(local.apache_operational_common_tags, { + tags = merge(local.operational_common_tags, { mitre_attack_id = "TA0040:T1499.004" # Impact:Application or System Exploitation }) } -query "apache_internal_server_error_occurred" { +query "internal_server_error_occurred" { sql = <<-EOQ select remote_addr as request_ip, @@ -54,20 +54,20 @@ EOQ } -detection "apache_missing_user_agent_detected" { - title = "Apache Missing User Agent Detected" - description = "Detect when an Apache web server received requests with missing user agent headers to check for potential automated tools, scripted attacks, or non-standard clients." +detection "missing_user_agent_detected" { + title = "Missing User Agent Detected" + description = "Detect when a web server received requests with missing user agent headers to check for potential automated tools, scripted attacks, or non-standard clients." severity = "medium" display_columns = local.detection_display_columns - query = query.apache_missing_user_agent_detected + query = query.missing_user_agent_detected - tags = merge(local.apache_operational_common_tags, { + tags = merge(local.operational_common_tags, { mitre_attack_id = "TA0043:T1592" # Reconnaissance:Gather Victim Host Information }) } -query "apache_missing_user_agent_detected" { +query "missing_user_agent_detected" { sql = <<-EOQ select remote_addr as request_ip, @@ -86,20 +86,20 @@ EOQ } -detection "apache_large_payload_request_detected" { - title = "Apache Large Payload Request Detected" - description = "Detect when an Apache web server processed requests with unusually large body sizes to check for potential file uploads, data exfiltration attempts, or resource consumption issues." +detection "large_payload_request_detected" { + title = "Large Payload Request Detected" + description = "Detect when a web server processed requests with unusually large body sizes to check for potential file uploads, data exfiltration attempts, or resource consumption issues." severity = "medium" display_columns = local.detection_display_columns - query = query.apache_large_payload_request_detected + query = query.large_payload_request_detected - tags = merge(local.apache_operational_common_tags, { + tags = merge(local.operational_common_tags, { mitre_attack_id = "TA0009:T1530,TA0010:T1048" # Collection:Data from Cloud Storage Object, Exfiltration:Exfiltration Over Alternative Protocol }) } -query "apache_large_payload_request_detected" { +query "large_payload_request_detected" { sql = <<-EOQ select remote_addr as request_ip, @@ -117,20 +117,20 @@ EOQ } -detection "apache_high_error_rate_detected" { - title = "Apache High Error Rate Detected" - description = "Detect when an Apache web server experienced a high rate of HTTP errors within a time window to check for potential service disruptions, application failures, or attack patterns." +detection "high_error_rate_detected" { + title = "High Error Rate Detected" + description = "Detect when a web server experienced a high rate of HTTP errors within a time window to check for potential service disruptions, application failures, or attack patterns." severity = "high" display_columns = local.detection_display_columns - query = query.apache_high_error_rate_detected + query = query.high_error_rate_detected - tags = merge(local.apache_operational_common_tags, { + tags = merge(local.operational_common_tags, { mitre_attack_id = "TA0040:T1499.002" # Impact:Service Exhaustion Flood }) } -query "apache_high_error_rate_detected" { +query "high_error_rate_detected" { sql = <<-EOQ with error_windows as ( select @@ -162,20 +162,20 @@ EOQ } -detection "apache_unusual_traffic_spike_detected" { - title = "Apache Unusual Traffic Spike Detected" - description = "Detect when an Apache web server experienced unusual spikes in traffic volume compared to historical patterns to check for potential DDoS attacks, viral content, or unexpected application behavior." +detection "unusual_traffic_spike_detected" { + title = "Unusual Traffic Spike Detected" + description = "Detect when a web server experienced unusual spikes in traffic volume compared to historical patterns to check for potential DDoS attacks, viral content, or unexpected application behavior." severity = "medium" display_columns = local.detection_display_columns - query = query.apache_unusual_traffic_spike_detected + query = query.unusual_traffic_spike_detected - tags = merge(local.apache_operational_common_tags, { + tags = merge(local.operational_common_tags, { mitre_attack_id = "TA0040:T1498,TA0040:T1499.002" # Impact:Network Denial of Service, Impact:Service Exhaustion Flood }) } -query "apache_unusual_traffic_spike_detected" { +query "unusual_traffic_spike_detected" { sql = <<-EOQ with traffic_windows as ( select @@ -207,20 +207,20 @@ EOQ } -detection "apache_endpoint_high_error_rate_detected" { - title = "Apache Endpoint High Error Rate Detected" - description = "Detect when an Apache web server processed requests to specific endpoints with unusually high error rates to check for broken functionality, misconfiguration, or targeted attacks against specific application components." +detection "endpoint_high_error_rate_detected" { + title = "Endpoint High Error Rate Detected" + description = "Detect when a web server processed requests to specific endpoints with unusually high error rates to check for broken functionality, misconfiguration, or targeted attacks against specific application components." severity = "high" display_columns = local.detection_display_columns - query = query.apache_endpoint_high_error_rate_detected + query = query.endpoint_high_error_rate_detected - tags = merge(local.apache_operational_common_tags, { + tags = merge(local.operational_common_tags, { mitre_attack_id = "TA0040:T1499.002,TA0001:T1190" # Impact:Service Exhaustion Flood, Initial Access:Exploit Public-Facing Application }) } -query "apache_endpoint_high_error_rate_detected" { +query "endpoint_high_error_rate_detected" { sql = <<-EOQ select request_uri as endpoint, @@ -243,20 +243,20 @@ EOQ } -detection "apache_client_error_pattern_detected" { - title = "Apache Client Error Pattern Detected" - description = "Detect when an Apache web server logged patterns in client-side errors (4xx) to check for potential client issues, invalid requests, or reconnaissance activities." +detection "client_error_pattern_detected" { + title = "Client Error Pattern Detected" + description = "Detect when a web server logged patterns in client-side errors (4xx) to check for potential client issues, invalid requests, or reconnaissance activities." severity = "medium" display_columns = local.detection_display_columns - query = query.apache_client_error_pattern_detected + query = query.client_error_pattern_detected - tags = merge(local.apache_operational_common_tags, { + tags = merge(local.operational_common_tags, { mitre_attack_id = "TA0001:T1190,TA0043:T1595" # Initial Access:Exploit Public-Facing Application, Reconnaissance:Active Scanning }) } -query "apache_client_error_pattern_detected" { +query "client_error_pattern_detected" { sql = <<-EOQ with client_errors as ( select @@ -303,20 +303,20 @@ EOQ } -detection "apache_server_error_pattern_detected" { - title = "Apache Server Error Pattern Detected" - description = "Detect when an Apache web server logged patterns in server-side errors (5xx) to check for potential server issues, application failures, or infrastructure problems." +detection "server_error_pattern_detected" { + title = "Server Error Pattern Detected" + description = "Detect when a web server logged patterns in server-side errors (5xx) to check for potential server issues, application failures, or infrastructure problems." severity = "high" display_columns = local.detection_display_columns - query = query.apache_server_error_pattern_detected + query = query.server_error_pattern_detected - tags = merge(local.apache_operational_common_tags, { + tags = merge(local.operational_common_tags, { mitre_attack_id = "TA0040:T1499.004,TA0040:T1499.003" # Impact:Application or System Exploitation, Impact:Application Exhaustion Flood }) } -query "apache_server_error_pattern_detected" { +query "server_error_pattern_detected" { sql = <<-EOQ with server_errors as ( select diff --git a/detections/apache_performance.pp b/detections/apache_performance.pp index b58c1a2..217269c 100644 --- a/detections/apache_performance.pp +++ b/detections/apache_performance.pp @@ -1,42 +1,42 @@ locals { - apache_performance_common_tags = merge(local.apache_access_log_detections_common_tags, { + performance_common_tags = merge(local.apache_access_log_detections_common_tags, { category = "Performance" }) } -benchmark "apache_performance_detections" { - title = "Apache Performance Detections" - description = "This benchmark contains performance-focused detections when scanning Apache access logs." +benchmark "performance_detections" { + title = "Performance Detections" + description = "This benchmark contains performance-focused detections when scanning access logs." type = "detection" children = [ - detection.apache_very_slow_request_detected, - detection.apache_large_static_file_requested, - detection.apache_request_timeout_occurred, - detection.apache_slow_response_time_detected, - detection.apache_response_time_anomaly_detected, - detection.apache_high_traffic_endpoint_detected, - detection.apache_connection_pool_exhaustion_risk_detected + detection.very_slow_request_detected, + detection.large_static_file_requested, + detection.request_timeout_occurred, + detection.slow_response_time_detected, + detection.response_time_anomaly_detected, + detection.high_traffic_endpoint_detected, + detection.connection_pool_exhaustion_risk_detected ] - tags = merge(local.apache_performance_common_tags, { + tags = merge(local.performance_common_tags, { type = "Benchmark" }) } -detection "apache_very_slow_request_detected" { - title = "Apache Very Slow Request Detected" - description = "Detect when an Apache web server processed HTTP requests with abnormally high response times to check for performance bottlenecks, resource contention, or potential DoS conditions." +detection "very_slow_request_detected" { + title = "Very Slow Request Detected" + description = "Detect when a web server processed HTTP requests with abnormally high response times to check for performance bottlenecks, resource contention, or potential DoS conditions." severity = "high" display_columns = local.detection_display_columns - query = query.apache_very_slow_request_detected + query = query.very_slow_request_detected - tags = merge(local.apache_performance_common_tags, { + tags = merge(local.performance_common_tags, { mitre_attack_id = "TA0040:T1499.003" # Impact:Application Exhaustion Flood }) } -query "apache_very_slow_request_detected" { +query "very_slow_request_detected" { sql = <<-EOQ select remote_addr as request_ip, @@ -54,20 +54,20 @@ EOQ } -detection "apache_large_static_file_requested" { - title = "Apache Large Static File Requested" - description = "Detect when an Apache web server processed requests for large static files to check for potential bandwidth consumption, server load issues, or content delivery optimization opportunities." +detection "large_static_file_requested" { + title = "Large Static File Requested" + description = "Detect when a web server processed requests for large static files to check for potential bandwidth consumption, server load issues, or content delivery optimization opportunities." severity = "medium" display_columns = local.detection_display_columns - query = query.apache_large_static_file_requested + query = query.large_static_file_requested - tags = merge(local.apache_performance_common_tags, { + tags = merge(local.performance_common_tags, { mitre_attack_id = "TA0040:T1499.002" # Impact:Service Exhaustion Flood }) } -query "apache_large_static_file_requested" { +query "large_static_file_requested" { sql = <<-EOQ select remote_addr as request_ip, @@ -109,20 +109,20 @@ EOQ } -detection "apache_request_timeout_occurred" { - title = "Apache Request Timeout Occurred" - description = "Detect when an Apache web server returned HTTP 408 Request Timeout or 504 Gateway Timeout errors to check for resource constraints, server overload, or slow upstream services." +detection "request_timeout_occurred" { + title = "Request Timeout Occurred" + description = "Detect when a web server returned HTTP 408 Request Timeout or 504 Gateway Timeout errors to check for resource constraints, server overload, or slow upstream services." severity = "high" display_columns = local.detection_display_columns - query = query.apache_request_timeout_occurred + query = query.request_timeout_occurred - tags = merge(local.apache_performance_common_tags, { + tags = merge(local.performance_common_tags, { mitre_attack_id = "TA0040:T1499.004" # Impact:Application or System Exploitation }) } -query "apache_request_timeout_occurred" { +query "request_timeout_occurred" { sql = <<-EOQ select remote_addr as request_ip, @@ -139,20 +139,20 @@ EOQ } -detection "apache_slow_response_time_detected" { - title = "Apache Slow Response Time Detected" - description = "Detect when an Apache web server processed requests to endpoints with consistently high response times to check for performance bottlenecks, inefficient code paths, or database query issues." +detection "slow_response_time_detected" { + title = "Slow Response Time Detected" + description = "Detect when a web server processed requests to endpoints with consistently high response times to check for performance bottlenecks, inefficient code paths, or database query issues." severity = "high" display_columns = local.detection_display_columns - query = query.apache_slow_response_time_detected + query = query.slow_response_time_detected - tags = merge(local.apache_performance_common_tags, { + tags = merge(local.performance_common_tags, { mitre_attack_id = "TA0040:T1499.003,TA0040:T1496.001" # Impact:Application Exhaustion Flood, Impact:Compute Hijacking }) } -query "apache_slow_response_time_detected" { +query "slow_response_time_detected" { sql = <<-EOQ with response_stats as ( select @@ -185,20 +185,20 @@ EOQ } -detection "apache_response_time_anomaly_detected" { - title = "Apache Response Time Anomaly Detected" - description = "Detect when an Apache web server experienced sudden increases in response time compared to historical patterns to check for performance degradation, service disruptions, or infrastructure changes." +detection "response_time_anomaly_detected" { + title = "Response Time Anomaly Detected" + description = "Detect when a web server experienced sudden increases in response time compared to historical patterns to check for performance degradation, service disruptions, or infrastructure changes." severity = "high" display_columns = local.detection_display_columns - query = query.apache_response_time_anomaly_detected + query = query.response_time_anomaly_detected - tags = merge(local.apache_performance_common_tags, { + tags = merge(local.performance_common_tags, { mitre_attack_id = "TA0040:T1499.003,TA0040:T1496.001" # Impact:Application Exhaustion Flood, Impact:Compute Hijacking }) } -query "apache_response_time_anomaly_detected" { +query "response_time_anomaly_detected" { sql = <<-EOQ with time_windows as ( select @@ -232,20 +232,20 @@ EOQ } -detection "apache_high_traffic_endpoint_detected" { - title = "Apache High Traffic Endpoint Detected" - description = "Detect when an Apache web server handled unusually high traffic volumes to specific endpoints to check for resource consumption patterns, hot spots in the application, or potential areas for optimization." +detection "high_traffic_endpoint_detected" { + title = "High Traffic Endpoint Detected" + description = "Detect when a web server handled unusually high traffic volumes to specific endpoints to check for resource consumption patterns, hot spots in the application, or potential areas for optimization." severity = "medium" display_columns = local.detection_display_columns - query = query.apache_high_traffic_endpoint_detected + query = query.high_traffic_endpoint_detected - tags = merge(local.apache_performance_common_tags, { + tags = merge(local.performance_common_tags, { mitre_attack_id = "TA0040:T1499.002,TA0040:T1498.001" # Impact:Service Exhaustion Flood, Impact:Direct Network Flood }) } -query "apache_high_traffic_endpoint_detected" { +query "high_traffic_endpoint_detected" { sql = <<-EOQ with endpoint_traffic as ( select @@ -281,20 +281,20 @@ EOQ } -detection "apache_connection_pool_exhaustion_risk_detected" { - title = "Apache Connection Pool Exhaustion Risk Detected" - description = "Detect when an Apache web server showed signs of connection pool exhaustion based on concurrent connections to check for capacity limits, resource constraints, or potential denial of service conditions." +detection "connection_pool_exhaustion_risk_detected" { + title = "Connection Pool Exhaustion Risk Detected" + description = "Detect when a web server showed signs of connection pool exhaustion based on concurrent connections to check for capacity limits, resource constraints, or potential denial of service conditions." severity = "critical" display_columns = local.detection_display_columns - query = query.apache_connection_pool_exhaustion_risk_detected + query = query.connection_pool_exhaustion_risk_detected - tags = merge(local.apache_performance_common_tags, { + tags = merge(local.performance_common_tags, { mitre_attack_id = "TA0040:T1499.002" # Impact:Service Exhaustion Flood }) } -query "apache_connection_pool_exhaustion_risk_detected" { +query "connection_pool_exhaustion_risk_detected" { sql = <<-EOQ with connection_stats as ( select diff --git a/detections/apache_security.pp b/detections/apache_security.pp index 3ac69aa..c3e7540 100644 --- a/detections/apache_security.pp +++ b/detections/apache_security.pp @@ -1,44 +1,48 @@ locals { - apache_security_common_tags = merge(local.apache_access_log_detections_common_tags, { + security_common_tags = merge(local.apache_access_log_detections_common_tags, { category = "Security" }) } -benchmark "apache_security_detections" { - title = "Apache Security Detections" - description = "This benchmark contains security-focused detections when scanning Apache access logs." +benchmark "security_detections" { + title = "Security Detections" + description = "This benchmark contains security-focused detections when scanning access logs." type = "detection" children = [ - detection.apache_sql_injection_attempted, - detection.apache_directory_traversal_attempted, - detection.apache_brute_force_auth_attempted, - detection.apache_suspicious_user_agent_detected, - detection.apache_xss_attempted, - detection.apache_sensitive_file_access_attempted, - detection.apache_unusual_http_method_used, - detection.apache_web_shell_access_attempted, - detection.apache_api_key_exposed + detection.api_key_exposed, + detection.brute_force_auth_attempted, + detection.data_privacy_requirement_violated, + detection.directory_traversal_attempted, + detection.pii_data_exposed_in_url, + detection.restricted_resource_accessed, + detection.sensitive_file_access_attempted, + detection.sql_injection_attempted, + detection.suspicious_user_agent_detected, + detection.unauthorized_ip_access_detected, + detection.unusual_http_method_used, + detection.web_shell_access_attempted, + detection.xss_attempted ] - tags = merge(local.apache_security_common_tags, { + tags = merge(local.security_common_tags, { type = "Benchmark" }) } -detection "apache_sql_injection_attempted" { - title = "Apache SQL Injection Attempted" - description = "Detect when an Apache web server was targeted by SQL injection attempts to check for potential database compromise, data theft, or unauthorized system access." +detection "sql_injection_attempted" { + title = "SQL Injection Attempted" + description = "Detect when a web server was targeted by SQL injection attempts to check for potential database compromise, data theft, or unauthorized system access." severity = "critical" display_columns = local.detection_display_columns - query = query.apache_sql_injection_attempted + query = query.sql_injection_attempted - tags = merge(local.apache_security_common_tags, { + tags = merge(local.security_common_tags, { mitre_attack_ids = "TA0009:T1190" }) } -query "apache_sql_injection_attempted" { +query "sql_injection_attempted" { sql = <<-EOQ select remote_addr as request_ip, @@ -65,20 +69,20 @@ EOQ } -detection "apache_directory_traversal_attempted" { - title = "Apache Directory Traversal Attempted" - description = "Detect when an Apache web server was targeted by directory traversal attempts to check for unauthorized access to sensitive files outside the web root directory." +detection "directory_traversal_attempted" { + title = "Directory Traversal Attempted" + description = "Detect when a web server was targeted by directory traversal attempts to check for unauthorized access to sensitive files outside the web root directory." severity = "high" display_columns = local.detection_display_columns - query = query.apache_directory_traversal_attempted + query = query.directory_traversal_attempted - tags = merge(local.apache_security_common_tags, { + tags = merge(local.security_common_tags, { mitre_attack_ids = "TA0009:T1083" }) } -query "apache_directory_traversal_attempted" { +query "directory_traversal_attempted" { sql = <<-EOQ select remote_addr as request_ip, @@ -106,20 +110,20 @@ EOQ } -detection "apache_brute_force_auth_attempted" { - title = "Apache Brute Force Authentication Attempted" - description = "Detect when an Apache web server was targeted by brute force authentication attempts to check for potential credential compromise and unauthorized access." +detection "brute_force_auth_attempted" { + title = "Brute Force Authentication Attempted" + description = "Detect when a web server was targeted by brute force authentication attempts to check for potential credential compromise and unauthorized access." severity = "high" display_columns = local.detection_display_columns - query = query.apache_brute_force_auth_attempted + query = query.brute_force_auth_attempted - tags = merge(local.apache_security_common_tags, { + tags = merge(local.security_common_tags, { mitre_attack_ids = "TA0009:T1110" }) } -query "apache_brute_force_auth_attempted" { +query "brute_force_auth_attempted" { sql = <<-EOQ select remote_addr as request_ip, @@ -157,20 +161,20 @@ EOQ } -detection "apache_suspicious_user_agent_detected" { - title = "Apache Suspicious User Agent Detected" - description = "Detect when an Apache web server received requests with known malicious user agents to check for reconnaissance activities and potential targeted attacks." +detection "suspicious_user_agent_detected" { + title = "Suspicious User Agent Detected" + description = "Detect when a web server received requests with known malicious user agents to check for reconnaissance activities and potential targeted attacks." severity = "medium" display_columns = local.detection_display_columns - query = query.apache_suspicious_user_agent_detected + query = query.suspicious_user_agent_detected - tags = merge(local.apache_security_common_tags, { + tags = merge(local.security_common_tags, { mitre_attack_ids = "TA0043:T1592" }) } -query "apache_suspicious_user_agent_detected" { +query "suspicious_user_agent_detected" { sql = <<-EOQ select remote_addr as request_ip, @@ -200,20 +204,20 @@ EOQ } -detection "apache_xss_attempted" { - title = "Apache Cross-Site Scripting Attempted" - description = "Detect when an Apache web server was targeted by cross-site scripting (XSS) attacks to check for potential client-side code injection that could lead to session hijacking or credential theft." +detection "xss_attempted" { + title = "Cross-Site Scripting Attempted" + description = "Detect when a web server was targeted by cross-site scripting (XSS) attacks to check for potential client-side code injection that could lead to session hijacking or credential theft." severity = "critical" display_columns = local.detection_display_columns - query = query.apache_xss_attempted + query = query.xss_attempted - tags = merge(local.apache_security_common_tags, { + tags = merge(local.security_common_tags, { mitre_attack_ids = "TA0009:T1059.007" }) } -query "apache_xss_attempted" { +query "xss_attempted" { sql = <<-EOQ select remote_addr as request_ip, @@ -243,20 +247,20 @@ EOQ } -detection "apache_sensitive_file_access_attempted" { - title = "Apache Sensitive File Access Attempted" - description = "Detect when an Apache web server received requests for sensitive files or directories to check for potential information disclosure, configuration leaks, or access to restricted resources." +detection "sensitive_file_access_attempted" { + title = "Sensitive File Access Attempted" + description = "Detect when a web server received requests for sensitive files or directories to check for potential information disclosure, configuration leaks, or access to restricted resources." severity = "high" display_columns = local.detection_display_columns - query = query.apache_sensitive_file_access_attempted + query = query.sensitive_file_access_attempted - tags = merge(local.apache_security_common_tags, { + tags = merge(local.security_common_tags, { mitre_attack_ids = "TA0009:T1083" }) } -query "apache_sensitive_file_access_attempted" { +query "sensitive_file_access_attempted" { sql = <<-EOQ select remote_addr as request_ip, @@ -295,20 +299,20 @@ EOQ } -detection "apache_unusual_http_method_used" { - title = "Apache Unusual HTTP Method Used" - description = "Detect when an Apache web server received requests using unusual or potentially dangerous HTTP methods to check for exploitation attempts, information disclosure, or unauthorized modifications." +detection "unusual_http_method_used" { + title = "Unusual HTTP Method Used" + description = "Detect when a web server received requests using unusual or potentially dangerous HTTP methods to check for exploitation attempts, information disclosure, or unauthorized modifications." severity = "medium" display_columns = local.detection_display_columns - query = query.apache_unusual_http_method_used + query = query.unusual_http_method_used - tags = merge(local.apache_security_common_tags, { + tags = merge(local.security_common_tags, { mitre_attack_ids = "TA0009:T1213" }) } -query "apache_unusual_http_method_used" { +query "unusual_http_method_used" { sql = <<-EOQ select remote_addr as request_ip, @@ -334,20 +338,20 @@ EOQ } -detection "apache_web_shell_access_attempted" { - title = "Apache Web Shell Access Attempted" - description = "Detect when an Apache web server received potential web shell upload or access attempts to check for backdoor installation, persistent access, or remote code execution." +detection "web_shell_access_attempted" { + title = "Web Shell Access Attempted" + description = "Detect when a web server received potential web shell upload or access attempts to check for backdoor installation, persistent access, or remote code execution." severity = "critical" display_columns = local.detection_display_columns - query = query.apache_web_shell_access_attempted + query = query.web_shell_access_attempted - tags = merge(local.apache_security_common_tags, { + tags = merge(local.security_common_tags, { mitre_attack_ids = "TA0003:T1505.003" }) } -query "apache_web_shell_access_attempted" { +query "web_shell_access_attempted" { sql = <<-EOQ select remote_addr as request_ip, @@ -389,20 +393,20 @@ EOQ } -detection "apache_api_key_exposed" { - title = "Apache API Key Exposed" - description = "Detect when an Apache web server logged potential API keys or tokens in URLs to check for credential exposure, which could lead to unauthorized access to external services or systems." +detection "api_key_exposed" { + title = "API Key Exposed" + description = "Detect when a web server logged potential API keys or tokens in URLs to check for credential exposure, which could lead to unauthorized access to external services or systems." severity = "critical" display_columns = local.detection_display_columns - query = query.apache_api_key_exposed + query = query.api_key_exposed - tags = merge(local.apache_security_common_tags, { + tags = merge(local.security_common_tags, { mitre_attack_ids = "TA0006:T1552" }) } -query "apache_api_key_exposed" { +query "api_key_exposed" { sql = <<-EOQ select remote_addr as request_ip, From 2ebb846745e3a0a9468cdf1efbb6eb0e9142ea7d Mon Sep 17 00:00:00 2001 From: Priyanka Chatterjee Date: Fri, 4 Apr 2025 19:34:52 +0530 Subject: [PATCH 08/62] Rename files --- .../{apache_access_logs.pp => access_logs.pp} | 0 detections/apache_compliance.pp | 206 ------------------ .../{apache_operational.pp => operational.pp} | 0 .../{apache_performance.pp => performance.pp} | 0 .../{apache_security.pp => security.pp} | 187 +++++++++++++++- 5 files changed, 186 insertions(+), 207 deletions(-) rename detections/{apache_access_logs.pp => access_logs.pp} (100%) delete mode 100644 detections/apache_compliance.pp rename detections/{apache_operational.pp => operational.pp} (100%) rename detections/{apache_performance.pp => performance.pp} (100%) rename detections/{apache_security.pp => security.pp} (68%) diff --git a/detections/apache_access_logs.pp b/detections/access_logs.pp similarity index 100% rename from detections/apache_access_logs.pp rename to detections/access_logs.pp diff --git a/detections/apache_compliance.pp b/detections/apache_compliance.pp deleted file mode 100644 index b2210d1..0000000 --- a/detections/apache_compliance.pp +++ /dev/null @@ -1,206 +0,0 @@ -locals { - compliance_common_tags = merge(local.apache_access_log_detections_common_tags, { - category = "Compliance" - }) -} - -benchmark "compliance_detections" { - title = "Compliance Detections" - description = "This benchmark contains compliance-focused detections when scanning access logs." - type = "detection" - children = [ - detection.pii_data_exposed_in_url, - detection.restricted_resource_accessed, - detection.unauthorized_ip_access_detected, - detection.data_privacy_requirement_violated - ] - - tags = merge(local.compliance_common_tags, { - type = "Benchmark" - }) -} - -detection "pii_data_exposed_in_url" { - title = "PII Data Exposed In URL" - description = "Detect when a web server logged Personally Identifiable Information (PII) in URLs to check for potential data privacy violations, regulatory non-compliance, and sensitive information disclosure." - severity = "critical" - display_columns = local.detection_display_columns - - query = query.pii_data_exposed_in_url - - tags = merge(local.compliance_common_tags, { - mitre_attack_id = "TA0006:T1552.001" # Credential Access:Credentials In Files - }) -} - -query "pii_data_exposed_in_url" { - sql = <<-EOQ - with pii_patterns as ( - select - request_uri as request_path, - remote_addr as request_ip, - status as status_code, - tp_timestamp as timestamp, - case - when request_uri ~ '[0-9]{3}-[0-9]{2}-[0-9]{4}' then 'SSN' - when request_uri ~ '[0-9]{16}' then 'Credit Card' - when request_uri ~ '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}' then 'Email' - when request_uri ~ '(?:password|passwd|pwd)=[^&]+' then 'Password' - when request_uri ~ '[0-9]{10}' then 'Phone Number' - end as pii_type - from - apache_access_log - where - request_uri is not null - and ( - request_uri ~ '[0-9]{3}-[0-9]{2}-[0-9]{4}' -- SSN pattern - or request_uri ~ '[0-9]{16}' -- Credit card pattern - or request_uri ~ '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}' -- Email pattern - or request_uri ~ '(?:password|passwd|pwd)=[^&]+' -- Password in URL - or request_uri ~ '[0-9]{10}' -- Phone number pattern - ) - ) - select - * - from - pii_patterns - order by - timestamp desc; - EOQ -} - -detection "restricted_resource_accessed" { - title = "Restricted Resource Accessed" - description = "Detect when a web server processed requests to restricted resources or administrative areas to check for unauthorized access attempts, privilege escalation, or security policy violations." - severity = "high" - display_columns = local.detection_display_columns - - query = query.restricted_resource_accessed - - tags = merge(local.compliance_common_tags, { - mitre_attack_id = "TA0001:T1190,TA0008:T1133" # Initial Access:Exploit Public-Facing Application, Lateral Movement:External Remote Services - }) -} - -query "restricted_resource_accessed" { - sql = <<-EOQ - select - remote_addr as request_ip, - request_uri as request_path, - request_method, - status as status_code, - tp_timestamp as timestamp - from - apache_access_log - where - request_uri is not null - and ( - lower(request_uri) like '%/admin%' - or lower(request_uri) like '%/manager%' - or lower(request_uri) like '%/console%' - or lower(request_uri) like '%/dashboard%' - or lower(request_uri) like '%/management%' - or lower(request_uri) like '%/phpmyadmin%' - or lower(request_uri) like '%/wp-admin%' - or lower(request_uri) like '%/administrator%' - - -- Apache-specific sensitive paths - or lower(request_uri) like '%/server-status%' - or lower(request_uri) like '%/server-info%' - or lower(request_uri) like '%/status%' - or lower(request_uri) like '%/balancer-manager%' - ) - and status != 404 -- Exclude 404s to reduce noise - order by - timestamp desc; - EOQ -} - -detection "unauthorized_ip_access_detected" { - title = "Unauthorized IP Access Detected" - description = "Detect when a web server received requests from unauthorized IP ranges or geographic locations to check for potential security policy violations, access control bypasses, or geofencing compliance issues." - severity = "high" - display_columns = local.detection_display_columns - - query = query.unauthorized_ip_access_detected - - tags = merge(local.compliance_common_tags, { - mitre_attack_id = "TA0008:T1133,TA0003:T1078.004" # Lateral Movement:External Remote Services, Persistence:Cloud Accounts - }) -} - -query "unauthorized_ip_access_detected" { - sql = <<-EOQ - with unauthorized_access as ( - select - remote_addr as request_ip, - count(*) as request_count, - min(tp_timestamp) as first_access, - max(tp_timestamp) as last_access - from - apache_access_log - where - remote_addr not like '10.%' - and remote_addr not like '172.%' - and remote_addr not like '192.168.%' - and remote_addr not like '127.%' - group by - remote_addr - ) - select - * - from - unauthorized_access - order by - request_count desc; - EOQ -} - -detection "data_privacy_requirement_violated" { - title = "Data Privacy Requirement Violated" - description = "Detect when a web server processed requests that potentially violate data privacy requirements to check for regulatory compliance issues, sensitive data handling violations, or privacy policy infractions." - severity = "high" - display_columns = local.detection_display_columns - - query = query.data_privacy_requirement_violated - - tags = merge(local.compliance_common_tags, { - mitre_attack_id = "TA0009:T1530,TA0006:T1552.001" # Collection:Data from Cloud Storage, Credential Access:Credentials In Files - }) -} - -query "data_privacy_requirement_violated" { - sql = <<-EOQ - with privacy_endpoints as ( - select - request_uri as endpoint, - count(*) as total_requests, - count(*) filter ( - where request_uri ~ '(?i)(ssn|email|password|credit|card|phone|address|dob|birth)' - ) as sensitive_data_count, - count(distinct remote_addr) as unique_ips - from - apache_access_log - where - request_uri is not null - -- Focus on API endpoints and form submissions - and (request_uri like '/api/%' or request_method = 'POST') - group by - request_uri - having - count(*) filter ( - where request_uri ~ '(?i)(ssn|email|password|credit|card|phone|address|dob|birth)' - ) > 0 - ) - select - endpoint, - total_requests, - sensitive_data_count, - unique_ips, - round((sensitive_data_count::float / total_requests * 100)::numeric, 2) as sensitive_data_percentage - from - privacy_endpoints - order by - sensitive_data_count desc; - EOQ -} \ No newline at end of file diff --git a/detections/apache_operational.pp b/detections/operational.pp similarity index 100% rename from detections/apache_operational.pp rename to detections/operational.pp diff --git a/detections/apache_performance.pp b/detections/performance.pp similarity index 100% rename from detections/apache_performance.pp rename to detections/performance.pp diff --git a/detections/apache_security.pp b/detections/security.pp similarity index 68% rename from detections/apache_security.pp rename to detections/security.pp index c3e7540..e0335b7 100644 --- a/detections/apache_security.pp +++ b/detections/security.pp @@ -434,4 +434,189 @@ order by tp_timestamp desc; EOQ -} \ No newline at end of file +} + +detection "pii_data_exposed_in_url" { + title = "PII Data Exposed In URL" + description = "Detect when a web server logged Personally Identifiable Information (PII) in URLs to check for potential data privacy violations, regulatory non-compliance, and sensitive information disclosure." + severity = "critical" + display_columns = local.detection_display_columns + + query = query.pii_data_exposed_in_url + + tags = merge(local.compliance_common_tags, { + mitre_attack_id = "TA0006:T1552.001" # Credential Access:Credentials In Files + }) +} + +query "pii_data_exposed_in_url" { + sql = <<-EOQ + with pii_patterns as ( + select + request_uri as request_path, + remote_addr as request_ip, + status as status_code, + tp_timestamp as timestamp, + case + when request_uri ~ '[0-9]{3}-[0-9]{2}-[0-9]{4}' then 'SSN' + when request_uri ~ '[0-9]{16}' then 'Credit Card' + when request_uri ~ '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}' then 'Email' + when request_uri ~ '(?:password|passwd|pwd)=[^&]+' then 'Password' + when request_uri ~ '[0-9]{10}' then 'Phone Number' + end as pii_type + from + apache_access_log + where + request_uri is not null + and ( + request_uri ~ '[0-9]{3}-[0-9]{2}-[0-9]{4}' -- SSN pattern + or request_uri ~ '[0-9]{16}' -- Credit card pattern + or request_uri ~ '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}' -- Email pattern + or request_uri ~ '(?:password|passwd|pwd)=[^&]+' -- Password in URL + or request_uri ~ '[0-9]{10}' -- Phone number pattern + ) + ) + select + * + from + pii_patterns + order by + timestamp desc; + EOQ +} + +detection "restricted_resource_accessed" { + title = "Restricted Resource Accessed" + description = "Detect when a web server processed requests to restricted resources or administrative areas to check for unauthorized access attempts, privilege escalation, or security policy violations." + severity = "high" + display_columns = local.detection_display_columns + + query = query.restricted_resource_accessed + + tags = merge(local.compliance_common_tags, { + mitre_attack_id = "TA0001:T1190,TA0008:T1133" # Initial Access:Exploit Public-Facing Application, Lateral Movement:External Remote Services + }) +} + +query "restricted_resource_accessed" { + sql = <<-EOQ + select + remote_addr as request_ip, + request_uri as request_path, + request_method, + status as status_code, + tp_timestamp as timestamp + from + apache_access_log + where + request_uri is not null + and ( + lower(request_uri) like '%/admin%' + or lower(request_uri) like '%/manager%' + or lower(request_uri) like '%/console%' + or lower(request_uri) like '%/dashboard%' + or lower(request_uri) like '%/management%' + or lower(request_uri) like '%/phpmyadmin%' + or lower(request_uri) like '%/wp-admin%' + or lower(request_uri) like '%/administrator%' + + -- Apache-specific sensitive paths + or lower(request_uri) like '%/server-status%' + or lower(request_uri) like '%/server-info%' + or lower(request_uri) like '%/status%' + or lower(request_uri) like '%/balancer-manager%' + ) + and status != 404 -- Exclude 404s to reduce noise + order by + timestamp desc; + EOQ +} + +detection "unauthorized_ip_access_detected" { + title = "Unauthorized IP Access Detected" + description = "Detect when a web server received requests from unauthorized IP ranges or geographic locations to check for potential security policy violations, access control bypasses, or geofencing compliance issues." + severity = "high" + display_columns = local.detection_display_columns + + query = query.unauthorized_ip_access_detected + + tags = merge(local.compliance_common_tags, { + mitre_attack_id = "TA0008:T1133,TA0003:T1078.004" # Lateral Movement:External Remote Services, Persistence:Cloud Accounts + }) +} + +query "unauthorized_ip_access_detected" { + sql = <<-EOQ + with unauthorized_access as ( + select + remote_addr as request_ip, + count(*) as request_count, + min(tp_timestamp) as first_access, + max(tp_timestamp) as last_access + from + apache_access_log + where + remote_addr not like '10.%' + and remote_addr not like '172.%' + and remote_addr not like '192.168.%' + and remote_addr not like '127.%' + group by + remote_addr + ) + select + * + from + unauthorized_access + order by + request_count desc; + EOQ +} + +detection "data_privacy_requirement_violated" { + title = "Data Privacy Requirement Violated" + description = "Detect when a web server processed requests that potentially violate data privacy requirements to check for regulatory compliance issues, sensitive data handling violations, or privacy policy infractions." + severity = "high" + display_columns = local.detection_display_columns + + query = query.data_privacy_requirement_violated + + tags = merge(local.compliance_common_tags, { + mitre_attack_id = "TA0009:T1530,TA0006:T1552.001" # Collection:Data from Cloud Storage, Credential Access:Credentials In Files + }) +} + +query "data_privacy_requirement_violated" { + sql = <<-EOQ + with privacy_endpoints as ( + select + request_uri as endpoint, + count(*) as total_requests, + count(*) filter ( + where request_uri ~ '(?i)(ssn|email|password|credit|card|phone|address|dob|birth)' + ) as sensitive_data_count, + count(distinct remote_addr) as unique_ips + from + apache_access_log + where + request_uri is not null + -- Focus on API endpoints and form submissions + and (request_uri like '/api/%' or request_method = 'POST') + group by + request_uri + having + count(*) filter ( + where request_uri ~ '(?i)(ssn|email|password|credit|card|phone|address|dob|birth)' + ) > 0 + ) + select + endpoint, + total_requests, + sensitive_data_count, + unique_ips, + round((sensitive_data_count::float / total_requests * 100)::numeric, 2) as sensitive_data_percentage + from + privacy_endpoints + order by + sensitive_data_count desc; + EOQ +} \ No newline at end of file From 1c3abc05c2bb6d1a49a74da12e7b2d6d8f857bcc Mon Sep 17 00:00:00 2001 From: Priyanka Chatterjee Date: Fri, 4 Apr 2025 21:05:02 +0530 Subject: [PATCH 09/62] Refactor detection --- detections/operational.pp | 19 ++--------- detections/performance.pp | 16 ++-------- detections/security.pp | 67 +++++++-------------------------------- locals.pp | 11 ++++--- 4 files changed, 25 insertions(+), 88 deletions(-) diff --git a/detections/operational.pp b/detections/operational.pp index 54d7821..6a7b60e 100644 --- a/detections/operational.pp +++ b/detections/operational.pp @@ -40,11 +40,7 @@ query "internal_server_error_occurred" { sql = <<-EOQ select - remote_addr as request_ip, - request_uri as request_path, - request_method, - status as status_code, - tp_timestamp as timestamp + ${local.detection_sql_columns} from apache_access_log where @@ -70,11 +66,7 @@ query "missing_user_agent_detected" { sql = <<-EOQ select - remote_addr as request_ip, - request_uri as request_path, - request_method, - status as status_code, - tp_timestamp as timestamp + ${local.detection_sql_columns} from apache_access_log where @@ -102,12 +94,7 @@ query "large_payload_request_detected" { sql = <<-EOQ select - remote_addr as request_ip, - request_uri as request_path, - request_method, - body_bytes_sent as body_bytes, - status as status_code, - tp_timestamp as timestamp + ${local.detection_sql_columns} from apache_access_log where diff --git a/detections/performance.pp b/detections/performance.pp index 217269c..c6ff199 100644 --- a/detections/performance.pp +++ b/detections/performance.pp @@ -39,12 +39,7 @@ query "very_slow_request_detected" { sql = <<-EOQ select - remote_addr as request_ip, - request_uri as request_path, - request_method, - request_time as response_time, - status as status_code, - tp_timestamp as timestamp + ${local.detection_sql_columns} from apache_access_log where @@ -70,8 +65,7 @@ query "large_static_file_requested" { sql = <<-EOQ select - remote_addr as request_ip, - request_uri as request_path, + ${local.detection_sql_columns} case when lower(request_uri) like '%.jpg' or lower(request_uri) like '%.jpeg' then 'Image (JPEG)' when lower(request_uri) like '%.png' then 'Image (PNG)' @@ -125,11 +119,7 @@ query "request_timeout_occurred" { sql = <<-EOQ select - remote_addr as request_ip, - request_uri as request_path, - request_method, - status as status_code, - tp_timestamp as timestamp + ${local.detection_sql_columns} from apache_access_log where diff --git a/detections/security.pp b/detections/security.pp index e0335b7..1f5a143 100644 --- a/detections/security.pp +++ b/detections/security.pp @@ -45,11 +45,7 @@ query "sql_injection_attempted" { sql = <<-EOQ select - remote_addr as request_ip, - request_uri as request_path, - request_method, - status as status_code, - tp_timestamp as timestamp + ${local.detection_sql_columns} from apache_access_log where @@ -85,11 +81,7 @@ query "directory_traversal_attempted" { sql = <<-EOQ select - remote_addr as request_ip, - request_uri as request_path, - request_method, - status as status_code, - tp_timestamp as timestamp + ${local.detection_sql_columns} from apache_access_log where @@ -126,11 +118,7 @@ query "brute_force_auth_attempted" { sql = <<-EOQ select - remote_addr as request_ip, - request_uri as request_path, - request_method, - status as status_code, - tp_timestamp as timestamp + ${local.detection_sql_columns} from apache_access_log where @@ -177,11 +165,7 @@ query "suspicious_user_agent_detected" { sql = <<-EOQ select - remote_addr as request_ip, - http_user_agent as user_agent, - request_uri as request_path, - status as status_code, - tp_timestamp as timestamp + ${local.detection_sql_columns} from apache_access_log where @@ -220,11 +204,7 @@ query "xss_attempted" { sql = <<-EOQ select - remote_addr as request_ip, - request_uri as request_path, - request_method, - status as status_code, - tp_timestamp as timestamp + ${local.detection_sql_columns} from apache_access_log where @@ -263,11 +243,7 @@ query "sensitive_file_access_attempted" { sql = <<-EOQ select - remote_addr as request_ip, - request_uri as request_path, - request_method, - status as status_code, - tp_timestamp as timestamp + ${local.detection_sql_columns} from apache_access_log where @@ -315,11 +291,7 @@ query "unusual_http_method_used" { sql = <<-EOQ select - remote_addr as request_ip, - request_method, - request_uri as request_path, - status as status_code, - tp_timestamp as timestamp + ${local.detection_sql_columns} from apache_access_log where @@ -354,11 +326,7 @@ query "web_shell_access_attempted" { sql = <<-EOQ select - remote_addr as request_ip, - request_uri as request_path, - request_method, - status as status_code, - tp_timestamp as timestamp + ${local.detection_sql_columns} from apache_access_log where @@ -409,8 +377,7 @@ query "api_key_exposed" { sql = <<-EOQ select - remote_addr as request_ip, - request_uri as request_path, + ${local.detection_sql_columns} case when request_uri ~ '(?i)[a-z0-9]{32,}' then 'Potential API Key' when request_uri ~ '(?i)bearer\s+[a-zA-Z0-9-._~+/]+=*' then 'Bearer Token' @@ -453,10 +420,7 @@ sql = <<-EOQ with pii_patterns as ( select - request_uri as request_path, - remote_addr as request_ip, - status as status_code, - tp_timestamp as timestamp, + ${local.detection_sql_columns} case when request_uri ~ '[0-9]{3}-[0-9]{2}-[0-9]{4}' then 'SSN' when request_uri ~ '[0-9]{16}' then 'Credit Card' @@ -501,11 +465,7 @@ query "restricted_resource_accessed" { sql = <<-EOQ select - remote_addr as request_ip, - request_uri as request_path, - request_method, - status as status_code, - tp_timestamp as timestamp + ${local.detection_sql_columns} from apache_access_log where @@ -549,10 +509,7 @@ sql = <<-EOQ with unauthorized_access as ( select - remote_addr as request_ip, - count(*) as request_count, - min(tp_timestamp) as first_access, - max(tp_timestamp) as last_access + ${local.detection_sql_columns} from apache_access_log where diff --git a/locals.pp b/locals.pp index 237338d..545fa4f 100644 --- a/locals.pp +++ b/locals.pp @@ -11,10 +11,12 @@ # dimensions. Do not edit directly. detection_sql_columns = <<-EOQ tp_timestamp as timestamp, - request_method || ' ' || request_uri as operation, + request_method, + request_uri, tp_source_ip as source_ip, - server_name as server, - tp_id as detection_id, + status, + server_name, + tp_id as source_id, * EOQ } @@ -26,8 +28,9 @@ "timestamp", "request_method", "request_uri", - "tp_source_ip", + "source_ip", "status", "server_name", + "source_id", ] } \ No newline at end of file From 4afdf920c5b374569ac8478396912ca1aa980713 Mon Sep 17 00:00:00 2001 From: Priyanka Chatterjee Date: Fri, 4 Apr 2025 21:05:19 +0530 Subject: [PATCH 10/62] Update access log detections and security tags --- detections/access_logs.pp | 1 - detections/security.pp | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/detections/access_logs.pp b/detections/access_logs.pp index 3c65e45..e6a96fb 100644 --- a/detections/access_logs.pp +++ b/detections/access_logs.pp @@ -6,7 +6,6 @@ benchmark.security_detections, benchmark.operational_detections, benchmark.performance_detections, - benchmark.compliance_detections ] tags = merge(local.apache_access_log_detections_common_tags, { diff --git a/detections/security.pp b/detections/security.pp index 1f5a143..0083c68 100644 --- a/detections/security.pp +++ b/detections/security.pp @@ -411,7 +411,7 @@ query = query.pii_data_exposed_in_url - tags = merge(local.compliance_common_tags, { + tags = merge(local.security_common_tags, { mitre_attack_id = "TA0006:T1552.001" # Credential Access:Credentials In Files }) } @@ -457,7 +457,7 @@ query = query.restricted_resource_accessed - tags = merge(local.compliance_common_tags, { + tags = merge(local.security_common_tags, { mitre_attack_id = "TA0001:T1190,TA0008:T1133" # Initial Access:Exploit Public-Facing Application, Lateral Movement:External Remote Services }) } @@ -500,7 +500,7 @@ query = query.unauthorized_ip_access_detected - tags = merge(local.compliance_common_tags, { + tags = merge(local.security_common_tags, { mitre_attack_id = "TA0008:T1133,TA0003:T1078.004" # Lateral Movement:External Remote Services, Persistence:Cloud Accounts }) } @@ -537,7 +537,7 @@ query = query.data_privacy_requirement_violated - tags = merge(local.compliance_common_tags, { + tags = merge(local.security_common_tags, { mitre_attack_id = "TA0009:T1530,TA0006:T1552.001" # Collection:Data from Cloud Storage, Credential Access:Credentials In Files }) } From 8325de8cb9876c6f84f2f18bda96f91cced2243f Mon Sep 17 00:00:00 2001 From: Priyanka Chatterjee Date: Fri, 4 Apr 2025 22:27:03 +0530 Subject: [PATCH 11/62] Refactor activity dashboard and local detection columns --- dashboards/activity_dashboard.pp | 10 +++++----- locals.pp | 14 ++++++-------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/dashboards/activity_dashboard.pp b/dashboards/activity_dashboard.pp index dd82c5b..be3459f 100644 --- a/dashboards/activity_dashboard.pp +++ b/dashboards/activity_dashboard.pp @@ -1,10 +1,10 @@ dashboard "activity_dashboard" { - title = "Apache Log Activity Dashboard" + title = "Access Log Activity Dashboard" documentation = file("./dashboards/docs/activity_dashboard.md") tags = { type = "Dashboard" - service = "Apache" + service = "Apache/AccessLog" } container { @@ -36,21 +36,21 @@ container { chart { - title = "Status Code Distribution" + title = "Requests by Status Code" query = query.activity_dashboard_status_distribution width = 6 type = "pie" } chart { - title = "HTTP Method Distribution" + title = "Requests by HTTP Method" query = query.activity_dashboard_method_distribution width = 6 type = "column" } chart { - title = "Requests per Day" + title = "Requests by Day" query = query.activity_dashboard_requests_per_day width = 6 type = "line" diff --git a/locals.pp b/locals.pp index 545fa4f..894c75b 100644 --- a/locals.pp +++ b/locals.pp @@ -11,11 +11,10 @@ # dimensions. Do not edit directly. detection_sql_columns = <<-EOQ tp_timestamp as timestamp, - request_method, - request_uri, + request_method || ' ' || request_uri as operation, + server_name as resource, + remote_user as actor, tp_source_ip as source_ip, - status, - server_name, tp_id as source_id, * EOQ @@ -26,11 +25,10 @@ # dimensions. Do not edit directly. detection_display_columns = [ "timestamp", - "request_method", - "request_uri", + "operation", + "resource", + "actor", "source_ip", - "status", - "server_name", "source_id", ] } \ No newline at end of file From afa1dd5c86f8817382f5047617201cf8b48fc52d Mon Sep 17 00:00:00 2001 From: Priyanka Chatterjee Date: Fri, 4 Apr 2025 23:52:48 +0530 Subject: [PATCH 12/62] Add documentation for detections --- detections/docs/api_key_exposed.md | 16 +++++++++++ detections/docs/brute_force_auth_attempted.md | 15 +++++++++++ .../docs/client_error_pattern_detected.md | 24 +++++++++++++++++ ...onnection_pool_exhaustion_risk_detected.md | 27 +++++++++++++++++++ .../docs/data_privacy_requirement_violated.md | 19 +++++++++++++ .../docs/directory_traversal_attempted.md | 18 +++++++++++++ .../docs/endpoint_high_error_rate_detected.md | 24 +++++++++++++++++ detections/docs/high_error_rate_detected.md | 25 +++++++++++++++++ .../docs/high_traffic_endpoint_detected.md | 26 ++++++++++++++++++ .../docs/internal_server_error_occurred.md | 19 +++++++++++++ .../docs/large_payload_request_detected.md | 20 ++++++++++++++ .../docs/large_static_file_requested.md | 25 +++++++++++++++++ .../docs/missing_user_agent_detected.md | 23 ++++++++++++++++ detections/docs/pii_data_exposed_in_url.md | 20 ++++++++++++++ detections/docs/request_timeout_occurred.md | 27 +++++++++++++++++++ .../docs/response_time_anomaly_detected.md | 27 +++++++++++++++++++ .../docs/restricted_resource_accessed.md | 21 +++++++++++++++ .../docs/sensitive_file_access_attempted.md | 22 +++++++++++++++ .../docs/server_error_pattern_detected.md | 27 +++++++++++++++++++ .../docs/slow_response_time_detected.md | 26 ++++++++++++++++++ detections/docs/sql_injection_attempted.md | 17 ++++++++++++ .../docs/suspicious_user_agent_detected.md | 19 +++++++++++++ .../docs/unauthorized_ip_access_detected.md | 17 ++++++++++++ detections/docs/unusual_http_method_used.md | 18 +++++++++++++ .../docs/unusual_traffic_spike_detected.md | 25 +++++++++++++++++ detections/docs/very_slow_request_detected.md | 25 +++++++++++++++++ detections/docs/web_shell_access_attempted.md | 19 +++++++++++++ detections/docs/xss_attempted.md | 19 +++++++++++++ detections/operational.pp | 8 ++++++ detections/performance.pp | 10 +++++-- detections/security.pp | 27 ++++++++++++++----- 31 files changed, 647 insertions(+), 8 deletions(-) create mode 100644 detections/docs/api_key_exposed.md create mode 100644 detections/docs/brute_force_auth_attempted.md create mode 100644 detections/docs/client_error_pattern_detected.md create mode 100644 detections/docs/connection_pool_exhaustion_risk_detected.md create mode 100644 detections/docs/data_privacy_requirement_violated.md create mode 100644 detections/docs/directory_traversal_attempted.md create mode 100644 detections/docs/endpoint_high_error_rate_detected.md create mode 100644 detections/docs/high_error_rate_detected.md create mode 100644 detections/docs/high_traffic_endpoint_detected.md create mode 100644 detections/docs/internal_server_error_occurred.md create mode 100644 detections/docs/large_payload_request_detected.md create mode 100644 detections/docs/large_static_file_requested.md create mode 100644 detections/docs/missing_user_agent_detected.md create mode 100644 detections/docs/pii_data_exposed_in_url.md create mode 100644 detections/docs/request_timeout_occurred.md create mode 100644 detections/docs/response_time_anomaly_detected.md create mode 100644 detections/docs/restricted_resource_accessed.md create mode 100644 detections/docs/sensitive_file_access_attempted.md create mode 100644 detections/docs/server_error_pattern_detected.md create mode 100644 detections/docs/slow_response_time_detected.md create mode 100644 detections/docs/sql_injection_attempted.md create mode 100644 detections/docs/suspicious_user_agent_detected.md create mode 100644 detections/docs/unauthorized_ip_access_detected.md create mode 100644 detections/docs/unusual_http_method_used.md create mode 100644 detections/docs/unusual_traffic_spike_detected.md create mode 100644 detections/docs/very_slow_request_detected.md create mode 100644 detections/docs/web_shell_access_attempted.md create mode 100644 detections/docs/xss_attempted.md diff --git a/detections/docs/api_key_exposed.md b/detections/docs/api_key_exposed.md new file mode 100644 index 0000000..06082d4 --- /dev/null +++ b/detections/docs/api_key_exposed.md @@ -0,0 +1,16 @@ +## Overview + +Detect when a web server logged potential API keys or tokens in URLs. API keys, tokens, and other credentials should never be included in URLs as they can be exposed in various ways including server logs, browser history, referrer headers, and bookmarks. When these sensitive credentials are exposed, attackers can use them to gain unauthorized access to external services or systems, potentially leading to data breaches, service abuse, or unauthorized actions on behalf of the compromised account. + +The detection identifies several types of exposed credentials in URL requests: +- Long alphanumeric strings that resemble API keys +- Bearer tokens in URLs +- Explicitly named API keys (key=, token=) +- Client secrets and other authentication credentials + +Exposed credentials in URLs represent a significant security risk as they can lead to unauthorized access to third-party services, data leaks, and financial impacts through service abuse or account takeover. + +**References**: + +- [CWE-598: Use of GET Request Method With Sensitive Query Strings](https://cwe.mitre.org/data/definitions/598.html) +- [CWE-259: Use of Hard-coded Password](https://cwe.mitre.org/data/definitions/259.html) \ No newline at end of file diff --git a/detections/docs/brute_force_auth_attempted.md b/detections/docs/brute_force_auth_attempted.md new file mode 100644 index 0000000..f81f5f7 --- /dev/null +++ b/detections/docs/brute_force_auth_attempted.md @@ -0,0 +1,15 @@ +## Overview + +Detect when a web server was targeted by brute force authentication attempts. Brute force attacks are a trial-and-error method used to obtain information such as user credentials or personal identification numbers. In a brute force attack, automated software is used to generate a large number of consecutive guesses as to the value of the desired data. These attacks target authentication mechanisms and can lead to unauthorized access to accounts, sensitive data exposure, and further system compromise. + +The detection identifies patterns often associated with brute force attempts, including: +- High frequency of requests to authentication-related paths (login, auth, password) +- Suspicious combinations of request methods and URLs +- Unusual patterns of successful and failed authentication attempts +- Repetitive access to credential-related endpoints + +These patterns can indicate automated tools or scripts being used to systematically test different username and password combinations against authentication endpoints. + +**References**: +- [OWASP Brute Force Attack](https://owasp.org/www-community/attacks/Brute_force_attack) +- [CWE-307: Improper Restriction of Excessive Authentication Attempts](https://cwe.mitre.org/data/definitions/307.html) \ No newline at end of file diff --git a/detections/docs/client_error_pattern_detected.md b/detections/docs/client_error_pattern_detected.md new file mode 100644 index 0000000..d671600 --- /dev/null +++ b/detections/docs/client_error_pattern_detected.md @@ -0,0 +1,24 @@ +## Overview + +Detect when a web server logged patterns in client-side errors (4xx). HTTP 4xx status codes indicate that the client's request contains errors or cannot be fulfilled for client-specific reasons, such as authentication failures, resource not found, or invalid data. Analyzing the distribution and patterns of these client errors can reveal important information about potential client issues, scanning activities, or targeted attacks against the web application. + +The detection analyzes client-side error patterns by: +- Aggregating HTTP status codes in the 400-499 range +- Identifying the most frequent client error codes +- Determining the relative percentage of each error type +- Finding the most common URIs associated with each error type + +Client error patterns may indicate: +- Authentication problems (401, 403 errors) +- Scanning or enumeration activities (many 404 errors) +- Deprecated or changed API endpoints (410 errors) +- Clients submitting malformed requests (400 errors) +- Reconnaissance prior to targeted attacks +- Broken links or outdated documentation + +Understanding client error patterns helps identify both operational issues and potential security threats, allowing for proactive mitigation. + +**References**: + +- [OWASP: Failure to Restrict URL Access](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/05-Authorization_Testing/02-Testing_for_Bypassing_Authorization_Schema) +- [CWE-352: Cross-Site Request Forgery](https://cwe.mitre.org/data/definitions/352.html) \ No newline at end of file diff --git a/detections/docs/connection_pool_exhaustion_risk_detected.md b/detections/docs/connection_pool_exhaustion_risk_detected.md new file mode 100644 index 0000000..f02f525 --- /dev/null +++ b/detections/docs/connection_pool_exhaustion_risk_detected.md @@ -0,0 +1,27 @@ +## Overview + +Detect when a web server showed signs of connection pool exhaustion based on concurrent connections. Web servers typically maintain connection pools with maximum limits on concurrent connections. As these pools approach capacity, the server may start to reject new connections, leading to degraded performance and potential service outages. This detection identifies periods of high connection volume or abnormal rejection rates that may indicate impending resource exhaustion. + +The detection identifies connection pool risks by: +- Analyzing connection volumes over 1-minute intervals +- Identifying periods with high concurrent connection counts (exceeding 100 connections) +- Monitoring for elevated rejection rates (HTTP 503 Service Unavailable errors) +- Flagging conditions that may precede complete connection pool exhaustion + +Connection pool exhaustion risks may indicate: +- Insufficient capacity planning for traffic levels +- Denial of service attempts (intentional or unintentional) +- Connection leaks in application code +- Misconfigured connection timeouts +- Load balancing issues +- Database connection pool problems +- Third-party service dependencies affecting connection handling + +Early detection of these conditions allows for proactive scaling, tuning of connection parameters, or mitigation of potential denial of service activities before complete service failure occurs. + +**References**: +- [MITRE ATT&CK: Service Exhaustion Flood (T1499.002)](https://attack.mitre.org/techniques/T1499/002/) +- [OWASP: Denial of Service](https://owasp.org/www-community/attacks/Denial_of_Service) +- [CWE-770: Allocation of Resources Without Limits or Throttling](https://cwe.mitre.org/data/definitions/770.html) +- [HTTP Status Code 503: Service Unavailable](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/503) +- [Apache HTTP Server: Connection Handling](https://httpd.apache.org/docs/2.4/mod/core.html#maxconnectionsperchild) \ No newline at end of file diff --git a/detections/docs/data_privacy_requirement_violated.md b/detections/docs/data_privacy_requirement_violated.md new file mode 100644 index 0000000..61810bf --- /dev/null +++ b/detections/docs/data_privacy_requirement_violated.md @@ -0,0 +1,19 @@ +## Overview + +Detect when a web server processed requests that potentially violate data privacy requirements. Organizations are increasingly subject to strict data privacy regulations and standards such as GDPR, CCPA, HIPAA, and PCI DSS, which mandate the protection of various types of sensitive data. This detection focuses on identifying API endpoints and form submissions that may be handling sensitive data, helping organizations maintain compliance and protect user privacy. + +The detection identifies suspicious patterns that may indicate data privacy violations: +- API endpoints or form submissions containing sensitive data patterns (SSN, email, password, credit card, etc.) +- Endpoints with high concentrations of sensitive data handling +- Unusual patterns in how sensitive data is processed +- Endpoints accessed from multiple unique IP addresses while handling sensitive information + +Violations of data privacy requirements can lead to regulatory fines, legal liability, reputational damage, and erosion of customer trust. This detection helps organizations identify and mitigate potential data privacy issues proactively. + +**References**: +- [MITRE ATT&CK: Data from Cloud Storage (T1530)](https://attack.mitre.org/techniques/T1530/) +- [MITRE ATT&CK: Credentials In Files (T1552.001)](https://attack.mitre.org/techniques/T1552/001/) +- [OWASP API Security Top 10: Mass Assignment](https://owasp.org/API-Security/editions/2019/en/0xa6-mass-assignment/) +- [CWE-359: Exposure of Private Personal Information to an Unauthorized Actor](https://cwe.mitre.org/data/definitions/359.html) +- [GDPR: Data Protection by Design and Default](https://gdpr-info.eu/art-25-gdpr/) +- [HIPAA: Protected Health Information Rules](https://www.hhs.gov/hipaa/for-professionals/privacy/index.html) \ No newline at end of file diff --git a/detections/docs/directory_traversal_attempted.md b/detections/docs/directory_traversal_attempted.md new file mode 100644 index 0000000..73b1c94 --- /dev/null +++ b/detections/docs/directory_traversal_attempted.md @@ -0,0 +1,18 @@ +## Overview + +Detect when a web server was targeted by directory traversal attempts. Directory traversal (also known as path traversal) is an attack that aims to access files and directories stored outside the web root folder by manipulating variables that reference files with "dot-dot-slash (../)" sequences and variations. By using this technique, attackers can access arbitrary files and directories stored on the file system, including application source code, configuration files, and critical system files. + +The detection identifies various directory traversal patterns in URL requests, including: +- Plain traversal sequences (`../`, `/../`, `/./`) +- URL-encoded variants (`%2e%2e%2f`, `%2E%2E%2F`) +- Double-encoded traversal attempts +- Other path manipulation techniques + +These patterns are strong indicators of reconnaissance activities or active exploitation attempts to gain unauthorized access to sensitive resources. + +**References**: +- [OWASP Path Traversal](https://owasp.org/www-community/attacks/Path_Traversal) +- [MITRE ATT&CK: File and Directory Discovery (T1083)](https://attack.mitre.org/techniques/T1083/) +- [CWE-22: Improper Limitation of a Pathname to a Restricted Directory](https://cwe.mitre.org/data/definitions/22.html) +- [Apache Security Tips: Directory Protection](https://httpd.apache.org/docs/2.4/misc/security_tips.html#directoryprotection) +- [Directory Traversal Prevention in Web Applications](https://cheatsheetseries.owasp.org/cheatsheets/File_System_Security_Cheat_Sheet.html) \ No newline at end of file diff --git a/detections/docs/endpoint_high_error_rate_detected.md b/detections/docs/endpoint_high_error_rate_detected.md new file mode 100644 index 0000000..947f03a --- /dev/null +++ b/detections/docs/endpoint_high_error_rate_detected.md @@ -0,0 +1,24 @@ +## Overview + +Detect when a web server processed requests to specific endpoints with unusually high error rates. While the previous "High Error Rate" detection focuses on overall server error patterns, this detection examines error rates at the individual endpoint level. This allows for the identification of specific problematic URLs, API endpoints, or resources that may be experiencing issues even when the overall system appears healthy. + +The detection identifies endpoints where: +- The total request volume exceeds a minimum threshold (5 requests) +- The error rate exceeds a significant threshold (10% of all requests to that endpoint) +- HTTP status codes in the 400-599 range occur at an abnormal frequency for specific URIs + +High error rates on specific endpoints may indicate: +- Broken functionality or bugs in specific application components +- Targeted attacks against vulnerable endpoints +- API versioning or compatibility issues +- Permission/authorization problems for specific resources +- Configuration issues affecting particular application areas + +This granular approach helps identify localized issues that might be missed when looking at overall system metrics, enabling more targeted troubleshooting and security response. + +**References**: +- [MITRE ATT&CK: Service Exhaustion Flood (T1499.002)](https://attack.mitre.org/techniques/T1499/002/) +- [MITRE ATT&CK: Exploit Public-Facing Application (T1190)](https://attack.mitre.org/techniques/T1190/) +- [OWASP API Security Top 10](https://owasp.org/API-Security/editions/2019/en/0xa9-improper-assets-management/) +- [CWE-754: Improper Check for Unusual or Exceptional Conditions](https://cwe.mitre.org/data/definitions/754.html) +- [Microservice Architecture and Security](https://www.nginx.com/blog/microservices-security-challenge/) \ No newline at end of file diff --git a/detections/docs/high_error_rate_detected.md b/detections/docs/high_error_rate_detected.md new file mode 100644 index 0000000..d5447d8 --- /dev/null +++ b/detections/docs/high_error_rate_detected.md @@ -0,0 +1,25 @@ +## Overview + +Detect when a web server experienced a high rate of HTTP errors within a time window. A sudden or sustained spike in error responses (HTTP 4xx and 5xx status codes) can indicate application problems, configuration issues, or potentially malicious activities such as scanning or attacks. This detection analyzes error rates over 5-minute windows to identify periods where error rates exceed normal thresholds. + +The detection identifies time periods where: +- The total request volume exceeds a minimum threshold (10 requests) +- The error rate exceeds a significant threshold (10% of all requests) +- HTTP status codes in the 400-599 range occur at an abnormal frequency + +High error rates may indicate: +- Application failures or bugs +- Server resource constraints +- Misconfiguration of services +- Ongoing scanning or probing attacks +- Active exploitation attempts against vulnerabilities +- Denial of service conditions + +Monitoring error rates helps detect both operational issues and potential security incidents in progress, allowing for more rapid investigation and response. + +**References**: +- [MITRE ATT&CK: Service Exhaustion Flood (T1499.002)](https://attack.mitre.org/techniques/T1499/002/) +- [OWASP Logging Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html) +- [CWE-400: Uncontrolled Resource Consumption](https://cwe.mitre.org/data/definitions/400.html) +- [HTTP Status Codes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status) +- [Apache HTTP Server: Logging Configuration](https://httpd.apache.org/docs/2.4/logs.html) \ No newline at end of file diff --git a/detections/docs/high_traffic_endpoint_detected.md b/detections/docs/high_traffic_endpoint_detected.md new file mode 100644 index 0000000..b05ad6d --- /dev/null +++ b/detections/docs/high_traffic_endpoint_detected.md @@ -0,0 +1,26 @@ +## Overview + +Detect when a web server handled unusually high traffic volumes to specific endpoints. Some endpoints naturally receive more traffic than others, but identifying the highest-traffic URIs helps pinpoint resource consumption patterns, application hot spots, and potential areas for optimization. This detection ranks endpoints by request volume to help identify where traffic is concentrated within the application. + +The detection identifies high traffic patterns by: +- Analyzing request counts for each unique URI path +- Calculating what percentage of overall traffic each endpoint receives +- Identifying endpoints that exceed a minimum request threshold (10 requests) +- Ranking endpoints based on traffic volume + +High traffic endpoints may indicate: +- Popular application features that may need additional optimization +- Potential candidates for caching or CDN delivery +- Resource-intensive operations that could benefit from scaling +- Endpoints that might be targets for rate limiting +- Traffic patterns that could inform architectural decisions +- Potential scanning or enumeration activities if traffic is unexpected + +Understanding traffic distribution helps prioritize performance optimization efforts and can highlight unexpected usage patterns that warrant investigation. + +**References**: +- [MITRE ATT&CK: Service Exhaustion Flood (T1499.002)](https://attack.mitre.org/techniques/T1499/002/) +- [MITRE ATT&CK: Direct Network Flood (T1498.001)](https://attack.mitre.org/techniques/T1498/001/) +- [OWASP: Denial of Service](https://owasp.org/www-community/attacks/Denial_of_Service) +- [CWE-770: Allocation of Resources Without Limits or Throttling](https://cwe.mitre.org/data/definitions/770.html) +- [Web Application Scalability Best Practices](https://aws.amazon.com/blogs/architecture/web-application-scaling-best-practices/) \ No newline at end of file diff --git a/detections/docs/internal_server_error_occurred.md b/detections/docs/internal_server_error_occurred.md new file mode 100644 index 0000000..db9c1b9 --- /dev/null +++ b/detections/docs/internal_server_error_occurred.md @@ -0,0 +1,19 @@ +## Overview + +Detect when a web server returned HTTP 500 Internal Server Error responses. A 500 Internal Server Error is a generic error message indicating that the server encountered an unexpected condition that prevented it from fulfilling the request. These errors typically indicate server-side problems such as application crashes, unhandled exceptions, misconfiguration, or resource constraints. Monitoring for 500 errors is critical for maintaining application reliability and identifying potential security issues. + +The detection focuses on identifying HTTP 500 status codes in web server logs, which may indicate: +- Application code errors or bugs +- Server configuration issues +- Resource constraints (memory, CPU, connections) +- Database connectivity problems +- Potential exploitation attempts triggering application failures + +A high rate of 500 errors can indicate service disruption, application instability, or possibly a security incident. Addressing these errors promptly is essential for maintaining service quality and preventing potential security vulnerabilities from being exploited. + +**References**: +- [MITRE ATT&CK: Application or System Exploitation (T1499.004)](https://attack.mitre.org/techniques/T1499/004/) +- [OWASP: Improper Error Handling](https://owasp.org/www-community/Improper_Error_Handling) +- [CWE-388: Error Handling](https://cwe.mitre.org/data/definitions/388.html) +- [HTTP Status Code 500: Internal Server Error](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500) +- [Apache HTTP Server: Debugging Server Errors](https://httpd.apache.org/docs/2.4/misc/security_tips.html#serversidedata) \ No newline at end of file diff --git a/detections/docs/large_payload_request_detected.md b/detections/docs/large_payload_request_detected.md new file mode 100644 index 0000000..32b3e9a --- /dev/null +++ b/detections/docs/large_payload_request_detected.md @@ -0,0 +1,20 @@ +## Overview + +Detect when a web server processed requests with unusually large body sizes. While legitimate applications may sometimes transfer large files, an unusually large HTTP payload can indicate potential file uploads, data exfiltration attempts, or attempts to consume server resources. This detection helps identify abnormal data transfer patterns that could represent security risks or operational issues. + +The detection identifies HTTP requests where the body size exceeds a significant threshold (10MB), which may indicate: +- Unauthorized file uploads (particularly executables or malicious content) +- Data exfiltration attempts where sensitive information is being extracted +- Denial of service attempts aimed at consuming server bandwidth or storage +- Misconfigured applications sending excessive data +- Potential abuse of file upload functionality + +Monitoring large payload transfers is important for preventing unauthorized data transfers, protecting server resources, and identifying potential security incidents. + +**References**: +- [MITRE ATT&CK: Data from Cloud Storage Object (T1530)](https://attack.mitre.org/techniques/T1530/) +- [MITRE ATT&CK: Exfiltration Over Alternative Protocol (T1048)](https://attack.mitre.org/techniques/T1048/) +- [OWASP Unrestricted File Upload](https://owasp.org/www-community/vulnerabilities/Unrestricted_File_Upload) +- [CWE-400: Uncontrolled Resource Consumption](https://cwe.mitre.org/data/definitions/400.html) +- [CWE-434: Unrestricted Upload of File with Dangerous Type](https://cwe.mitre.org/data/definitions/434.html) +- [Apache HTTP Server: Limiting Request Body](https://httpd.apache.org/docs/2.4/mod/core.html#limitrequestbody) \ No newline at end of file diff --git a/detections/docs/large_static_file_requested.md b/detections/docs/large_static_file_requested.md new file mode 100644 index 0000000..068001a --- /dev/null +++ b/detections/docs/large_static_file_requested.md @@ -0,0 +1,25 @@ +## Overview + +Detect when a web server processed requests for large static files. While serving static content is a normal function of web servers, unusually large static file transfers can impact server performance, consume significant bandwidth, and potentially indicate content distribution issues or attempts to cause resource exhaustion. This detection identifies requests for large static files such as images, videos, documents, and archives that exceed typical size thresholds. + +The detection identifies requests where: +- The file size exceeds a significant threshold (5MB) +- The requested resource is a recognizable static file type (images, videos, documents, archives) +- The transfer may consume substantial server resources + +Large static file requests may indicate: +- Inefficient content delivery (files that should be served via CDN) +- Potential bandwidth consumption issues +- Media files that should be optimized or compressed +- Files that might benefit from streaming rather than direct download +- Potential denial of service through resource exhaustion +- Large data exfiltration attempts disguised as static file downloads + +Monitoring large static file transfers helps identify opportunities for performance optimization and detects potential resource abuse. + +**References**: +- [MITRE ATT&CK: Service Exhaustion Flood (T1499.002)](https://attack.mitre.org/techniques/T1499/002/) +- [OWASP Performance Testing Guidance](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/10-Business_Logic_Testing/07-Test_Defenses_Against_Application_Misuse) +- [CWE-770: Allocation of Resources Without Limits or Throttling](https://cwe.mitre.org/data/definitions/770.html) +- [Web Content Optimization Best Practices](https://developers.google.com/speed/docs/insights/OptimizeImages) +- [Apache HTTP Server: Content Negotiation](https://httpd.apache.org/docs/2.4/content-negotiation.html) \ No newline at end of file diff --git a/detections/docs/missing_user_agent_detected.md b/detections/docs/missing_user_agent_detected.md new file mode 100644 index 0000000..fe712c1 --- /dev/null +++ b/detections/docs/missing_user_agent_detected.md @@ -0,0 +1,23 @@ +## Overview + +Detect when a web server received requests with missing user agent headers. The User-Agent HTTP header field normally contains information about the client application, operating system, vendor, or version making the request. When this header is missing, empty, or explicitly nullified, it often indicates automated tools, scripts, or potential security scanning activities rather than legitimate user browser traffic. + +The detection identifies requests where the user agent header is: +- Completely absent (null) +- Empty strings ('') +- Placeholder values ('-') + +Missing user agent headers may indicate: +- Automated scanning tools or scripts +- Custom attack tools that don't properly emulate browsers +- Deliberate attempts to avoid detection by not presenting identifying information +- Reconnaissance activities prior to targeted attacks + +While some legitimate scripts and API clients might not include user agent headers, a pattern of requests without this information can be a signal of potentially suspicious activity that warrants investigation. + +**References**: +- [MITRE ATT&CK: Gather Victim Host Information (T1592)](https://attack.mitre.org/techniques/T1592/) +- [OWASP Web Security Testing Guide: Fingerprint Web Server](https://owasp.org/www-project-web-security-testing-guide/stable/4-Web_Application_Security_Testing/01-Information_Gathering/01-Conduct_Search_Engine_Discovery_Reconnaissance_for_Information_Leakage) +- [RFC 7231: User-Agent](https://tools.ietf.org/html/rfc7231#section-5.5.3) +- [CWE-200: Exposure of Sensitive Information to an Unauthorized Actor](https://cwe.mitre.org/data/definitions/200.html) +- [Apache ModSecurity: User Agent Filtering](https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-(v2.x)#useragent) \ No newline at end of file diff --git a/detections/docs/pii_data_exposed_in_url.md b/detections/docs/pii_data_exposed_in_url.md new file mode 100644 index 0000000..5704215 --- /dev/null +++ b/detections/docs/pii_data_exposed_in_url.md @@ -0,0 +1,20 @@ +## Overview + +Detect when a web server logged Personally Identifiable Information (PII) in URLs. PII is any data that could potentially identify a specific individual, such as Social Security numbers, credit card numbers, email addresses, phone numbers, and passwords. Including this sensitive information in URLs is a significant privacy and security risk as URLs are commonly logged in server logs, browser history, and proxy servers, and can be exposed in referrer headers when users navigate between sites. + +The detection identifies several types of PII that may be exposed in URL requests: +- Social Security Numbers (SSN) with pattern 123-45-6789 +- Credit card numbers (16-digit sequences) +- Email addresses +- Passwords or password parameters +- Phone numbers (10-digit sequences) + +Exposing PII in URLs violates data privacy best practices and potentially regulatory requirements such as GDPR, CCPA, and PCI-DSS. This exposure creates risk of identity theft, financial fraud, and privacy violations for users whose information is compromised. + +**References**: +- [MITRE ATT&CK: Credentials In Files (T1552.001)](https://attack.mitre.org/techniques/T1552/001/) +- [OWASP: Information Exposure Through Query Strings in URL](https://owasp.org/www-community/vulnerabilities/Information_exposure_through_query_strings_in_url) +- [CWE-598: Use of GET Request Method With Sensitive Query Strings](https://cwe.mitre.org/data/definitions/598.html) +- [CWE-312: Cleartext Storage of Sensitive Information](https://cwe.mitre.org/data/definitions/312.html) +- [GDPR: Personal Data Protection](https://gdpr-info.eu/issues/personal-data/) +- [PCI DSS: Requirements for Protecting Cardholder Data](https://www.pcisecuritystandards.org/) \ No newline at end of file diff --git a/detections/docs/request_timeout_occurred.md b/detections/docs/request_timeout_occurred.md new file mode 100644 index 0000000..e641ef4 --- /dev/null +++ b/detections/docs/request_timeout_occurred.md @@ -0,0 +1,27 @@ +## Overview + +Detect when a web server returned HTTP 408 Request Timeout or 504 Gateway Timeout errors. Timeout errors occur when a request takes too long to complete, either due to client delays in sending the complete request (408) or when a gateway or proxy server does not receive a timely response from an upstream server (504). These errors can indicate resource constraints, server overload, network issues, or problems with dependent services. + +The detection identifies HTTP requests where: +- HTTP status code 408 (Request Timeout) is returned, indicating client-side delays +- HTTP status code 504 (Gateway Timeout) is returned, indicating upstream server delays +- Either timeout condition indicates potential service disruption + +Request timeout errors may indicate: +- Server resource constraints (CPU, memory, connections) +- Network latency or connectivity issues +- Overloaded upstream services or dependencies +- Database query timeouts +- Long-running processes consuming server resources +- Partial denial of service conditions +- Misconfigured timeout settings + +Identifying timeout patterns helps diagnose performance bottlenecks, infrastructure issues, and potential security concerns before they escalate to complete service outages. + +**References**: +- [MITRE ATT&CK: Application or System Exploitation (T1499.004)](https://attack.mitre.org/techniques/T1499/004/) +- [HTTP Status Code 408: Request Timeout](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/408) +- [HTTP Status Code 504: Gateway Timeout](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/504) +- [CWE-400: Uncontrolled Resource Consumption](https://cwe.mitre.org/data/definitions/400.html) +- [Apache mod_reqtimeout: Request Timeout Configuration](https://httpd.apache.org/docs/2.4/mod/mod_reqtimeout.html) +- [Apache mod_proxy: Timeout Configuration](https://httpd.apache.org/docs/2.4/mod/mod_proxy.html) \ No newline at end of file diff --git a/detections/docs/response_time_anomaly_detected.md b/detections/docs/response_time_anomaly_detected.md new file mode 100644 index 0000000..a814f7a --- /dev/null +++ b/detections/docs/response_time_anomaly_detected.md @@ -0,0 +1,27 @@ +## Overview + +Detect when a web server experienced sudden increases in response time compared to historical patterns. This detection focuses on identifying temporal anomalies in performance metrics by comparing current response times to a rolling historical average. Unlike the previous performance detections that examine absolute thresholds, this approach identifies relative degradations in performance that might otherwise go unnoticed. + +The detection identifies performance anomalies by: +- Analyzing average response times across 5-minute intervals +- Comparing current performance to a rolling historical average from previous time periods +- Identifying periods where response times increase significantly (50% or more) from baseline +- Filtering out normal fluctuations by requiring a minimum historical baseline + +Response time anomalies may indicate: +- Gradual service degradation that hasn't yet reached critical levels +- Infrastructure changes impacting performance +- Database slowdowns or growing query complexity +- Memory leaks or resource consumption issues +- New code deployments with unexpected performance impacts +- Periodic batch processes affecting overall system performance +- Early indicators of denial of service conditions + +Detecting these relative changes in performance helps identify issues before they reach critical thresholds and impact user experience. + +**References**: +- [MITRE ATT&CK: Application Exhaustion Flood (T1499.003)](https://attack.mitre.org/techniques/T1499/003/) +- [MITRE ATT&CK: Compute Hijacking (T1496.001)](https://attack.mitre.org/techniques/T1496/001/) +- [OWASP: Application Performance Management](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/10-Business_Logic_Testing/07-Test_Defenses_Against_Application_Misuse) +- [CWE-400: Uncontrolled Resource Consumption](https://cwe.mitre.org/data/definitions/400.html) +- [Time Series Anomaly Detection](https://medium.com/towards-artificial-intelligence/time-series-anomaly-detection-using-lstm-encoder-decoder-models-a1c4bd8d97e1) \ No newline at end of file diff --git a/detections/docs/restricted_resource_accessed.md b/detections/docs/restricted_resource_accessed.md new file mode 100644 index 0000000..27d9644 --- /dev/null +++ b/detections/docs/restricted_resource_accessed.md @@ -0,0 +1,21 @@ +## Overview + +Detect when a web server processed requests to restricted resources or administrative areas. Administrative interfaces, management consoles, and other sensitive areas of web applications should be protected from unauthorized access. Attempts to access these resources may indicate reconnaissance activities or active exploitation attempts targeting privileged functionality, which could lead to unauthorized administrative actions, privilege escalation, or complete system compromise. + +The detection identifies requests to commonly restricted paths and directories, including: +- Administrative interfaces (`/admin`, `/administrator`) +- Management consoles (`/manager`, `/management`) +- Dashboard interfaces (`/console`, `/dashboard`) +- Database management tools (`/phpmyadmin`) +- Content management system admin areas (`/wp-admin`) +- Web server status and information pages (`/server-status`, `/server-info`) +- Load balancer management interfaces (`/balancer-manager`) + +Unauthorized access to these restricted resources could allow attackers to manipulate system settings, create backdoors, escalate privileges, or gain access to sensitive data, representing a significant security risk to the organization. + +**References**: +- [MITRE ATT&CK: Exploit Public-Facing Application (T1190)](https://attack.mitre.org/techniques/T1190/) +- [MITRE ATT&CK: External Remote Services (T1133)](https://attack.mitre.org/techniques/T1133/) +- [OWASP Broken Access Control](https://owasp.org/Top10/A01_2021-Broken_Access_Control/) +- [CWE-284: Improper Access Control](https://cwe.mitre.org/data/definitions/284.html) +- [Apache HTTP Server: Securing Admin Interfaces](https://httpd.apache.org/docs/2.4/howto/auth.html) \ No newline at end of file diff --git a/detections/docs/sensitive_file_access_attempted.md b/detections/docs/sensitive_file_access_attempted.md new file mode 100644 index 0000000..dfc71de --- /dev/null +++ b/detections/docs/sensitive_file_access_attempted.md @@ -0,0 +1,22 @@ +## Overview + +Detect when a web server received requests for sensitive files or directories. Attackers often probe web servers for configuration files, backup files, or other sensitive resources that might have been inadvertently exposed. These files can contain valuable information such as database credentials, API keys, internal network details, or application source code that could be leveraged for deeper compromises. + +The detection identifies requests for several categories of potentially sensitive files and directories: +- Configuration files (`.conf`, `.config`, `web.xml`) +- System files (`/etc/`) +- Environment files (`.env`) +- Source code repositories (`.git/`) +- Database files (`.sql`) +- Backup files (`backup`, `dump`) +- Web server specific files (`httpd.conf`, `.htpasswd`, `.htaccess`) +- Server status and information pages (`/server-status`, `/server-info`) + +Unauthorized access to these resources can lead to information disclosure, credential theft, privilege escalation, and further exploitation of the system. + +**References**: +- [MITRE ATT&CK: File and Directory Discovery (T1083)](https://attack.mitre.org/techniques/T1083/) +- [OWASP Sensitive Data Exposure](https://owasp.org/www-project-top-ten/2017/A3_2017-Sensitive_Data_Exposure) +- [CWE-538: Insertion of Sensitive Information into Externally-Accessible File or Directory](https://cwe.mitre.org/data/definitions/538.html) +- [Apache Security: Securing Files](https://httpd.apache.org/docs/2.4/misc/security_tips.html#protectserverfiles) +- [Server-Side Request Forgery Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html) \ No newline at end of file diff --git a/detections/docs/server_error_pattern_detected.md b/detections/docs/server_error_pattern_detected.md new file mode 100644 index 0000000..7257912 --- /dev/null +++ b/detections/docs/server_error_pattern_detected.md @@ -0,0 +1,27 @@ +## Overview + +Detect when a web server logged patterns in server-side errors (5xx). HTTP 5xx status codes indicate server-side problems that prevented the fulfillment of otherwise valid client requests. These errors often point to more serious underlying issues such as application crashes, resource constraints, or configuration problems. Analyzing the distribution and patterns of server errors can reveal important information about system health, potential vulnerabilities, and possible exploitation attempts. + +The detection analyzes server-side error patterns by: +- Aggregating HTTP status codes in the 500-599 range +- Identifying the most frequent server error codes +- Determining the relative percentage of each error type +- Finding the most common URIs associated with each error type + +Server error patterns may indicate: +- Application code failures (500 Internal Server Error) +- Gateway or proxy issues (502 Bad Gateway, 504 Gateway Timeout) +- Server overload conditions (503 Service Unavailable) +- Potential exploitation attempts triggering application crashes +- Infrastructure or configuration problems +- Deployment issues with new code + +Understanding server error patterns is critical for maintaining application availability, performance, and security. + +**References**: +- [MITRE ATT&CK: Application or System Exploitation (T1499.004)](https://attack.mitre.org/techniques/T1499/004/) +- [MITRE ATT&CK: Application Exhaustion Flood (T1499.003)](https://attack.mitre.org/techniques/T1499/003/) +- [OWASP: Improper Error Handling](https://owasp.org/www-community/Improper_Error_Handling) +- [HTTP Status Code Definitions: 5xx Server Error](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html) +- [CWE-388: Error Handling](https://cwe.mitre.org/data/definitions/388.html) +- [Apache HTTP Server: Handling Server Errors](https://httpd.apache.org/docs/2.4/misc/security_tips.html#serversidedata) \ No newline at end of file diff --git a/detections/docs/slow_response_time_detected.md b/detections/docs/slow_response_time_detected.md new file mode 100644 index 0000000..2350493 --- /dev/null +++ b/detections/docs/slow_response_time_detected.md @@ -0,0 +1,26 @@ +## Overview + +Detect when a web server processed requests to endpoints with consistently high response times. Unlike the "Very Slow Request Detected" detection that identifies individual slow requests, this detection analyzes endpoint performance more holistically by examining the average and maximum response times for specific URIs over multiple requests. This approach helps identify chronically problematic endpoints that may need optimization, even if individual requests don't exceed extreme thresholds. + +The detection identifies endpoints where: +- Multiple requests have been processed (minimum of 5 requests) +- The average response time exceeds a significant threshold (1 second) +- OR the maximum response time exceeds a higher threshold (3 seconds) +- Performance issues appear to be endpoint-specific rather than system-wide + +Consistently slow response times may indicate: +- Inefficient database queries associated with specific endpoints +- N+1 query problems or other code inefficiencies +- Resource-intensive operations that may need optimization +- Missing indexes or caching opportunities +- Endpoints that handle larger data volumes +- Backend service dependencies that are consistently slow + +Identifying chronically slow endpoints helps prioritize performance optimization efforts and avoid gradual service degradation over time. + +**References**: +- [MITRE ATT&CK: Application Exhaustion Flood (T1499.003)](https://attack.mitre.org/techniques/T1499/003/) +- [MITRE ATT&CK: Compute Hijacking (T1496.001)](https://attack.mitre.org/techniques/T1496/001/) +- [OWASP: Security Performance Testing](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/10-Business_Logic_Testing/07-Test_Defenses_Against_Application_Misuse) +- [CWE-1005: Input Validation for Unexpected Parameter](https://cwe.mitre.org/data/definitions/1005.html) +- [Web Performance Optimization](https://web.dev/fast/) \ No newline at end of file diff --git a/detections/docs/sql_injection_attempted.md b/detections/docs/sql_injection_attempted.md new file mode 100644 index 0000000..2249928 --- /dev/null +++ b/detections/docs/sql_injection_attempted.md @@ -0,0 +1,17 @@ +## Overview + +Detect when a web server was targeted by SQL injection attempts. SQL injection is a code injection technique that exploits vulnerabilities in applications that process SQL queries, allowing attackers to manipulate database queries to access, modify, or delete data without proper authorization. These attacks can lead to unauthorized access to sensitive data, data breaches, and potentially complete compromise of affected databases and systems. + +The detection identifies SQL-like syntax and patterns in URL requests that may indicate SQL injection attempts, such as: +- SELECT FROM patterns +- UNION SELECT patterns +- INSERT INTO patterns +- DELETE FROM patterns +- Common SQL injection test conditions like `OR 1=1` + +**References**: +- [OWASP SQL Injection Guide](https://owasp.org/www-community/attacks/SQL_Injection) +- [MITRE ATT&CK: Exploit Public-Facing Application (T1190)](https://attack.mitre.org/techniques/T1190/) +- [SQL Injection Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html) +- [CWE-89: Improper Neutralization of Special Elements used in an SQL Command](https://cwe.mitre.org/data/definitions/89.html) +- [Apache Web Server Security Best Practices](https://httpd.apache.org/docs/2.4/misc/security_tips.html) \ No newline at end of file diff --git a/detections/docs/suspicious_user_agent_detected.md b/detections/docs/suspicious_user_agent_detected.md new file mode 100644 index 0000000..0d2aba4 --- /dev/null +++ b/detections/docs/suspicious_user_agent_detected.md @@ -0,0 +1,19 @@ +## Overview + +Detect when a web server received requests with known malicious user agents. The User-Agent HTTP header identifies the client application, operating system, vendor, or version of the requesting user agent. Many penetration testing tools, vulnerability scanners, and malicious bots use distinctive user-agent strings that can be identified. These tools are often used for reconnaissance activities prior to more targeted attacks or as part of active exploitation attempts. + +The detection identifies requests with user-agent strings associated with: +- Security testing tools (SQLmap, Nikto, Nmap, etc.) +- Web vulnerability scanners (Burp Suite, Nessus, etc.) +- Directory enumeration tools (Gobuster, Dirbuster, etc.) +- Password cracking tools (Hydra, etc.) +- Missing or null user-agent strings (which can indicate automated scripts) + +Detecting these user agents early can help identify reconnaissance activities before they lead to successful exploitation. + +**References**: +- [MITRE ATT&CK: Gather Victim Host Information (T1592)](https://attack.mitre.org/techniques/T1592/) +- [OWASP Automated Threat Handbook](https://owasp.org/www-project-automated-threats-to-web-applications/) +- [User Agent Strings - Web Application Security Testing](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/01-Information_Gathering/03-Review_Webserver_Metafiles_for_Information_Leakage) +- [CWE-200: Exposure of Sensitive Information to an Unauthorized Actor](https://cwe.mitre.org/data/definitions/200.html) +- [Apache Module mod_security: User Agent Filtering](https://httpd.apache.org/docs/2.4/mod/mod_security.html) \ No newline at end of file diff --git a/detections/docs/unauthorized_ip_access_detected.md b/detections/docs/unauthorized_ip_access_detected.md new file mode 100644 index 0000000..1fa2042 --- /dev/null +++ b/detections/docs/unauthorized_ip_access_detected.md @@ -0,0 +1,17 @@ +## Overview + +Detect when a web server received requests from unauthorized IP ranges or geographic locations. Many organizations implement network segmentation and access control based on IP address ranges to enforce the principle of least privilege and reduce the attack surface. Connections from unexpected IP addresses, particularly those outside of known corporate networks or from unexpected geographic regions, may indicate unauthorized access attempts, potential breaches, or misconfigured access controls. + +The detection identifies access attempts from IP addresses outside of expected private network ranges: +- Access from non-RFC1918 private network addresses (outside of 10.x.x.x, 172.16-31.x.x, 192.168.x.x) +- Access from non-localhost addresses (outside of 127.x.x.x) +- Connections from potentially unauthorized external networks + +This detection can help identify security policy violations, geofencing compliance issues, or potentially malicious activities originating from unexpected sources. + +**References**: +- [MITRE ATT&CK: External Remote Services (T1133)](https://attack.mitre.org/techniques/T1133/) +- [MITRE ATT&CK: Cloud Accounts (T1078.004)](https://attack.mitre.org/techniques/T1078/004/) +- [OWASP: Authentication Cheat Sheet - IP-Based Authentication](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html#ip-based-authentication) +- [CWE-284: Improper Access Control](https://cwe.mitre.org/data/definitions/284.html) +- [Apache HTTP Server: Access Control](https://httpd.apache.org/docs/2.4/howto/access.html) \ No newline at end of file diff --git a/detections/docs/unusual_http_method_used.md b/detections/docs/unusual_http_method_used.md new file mode 100644 index 0000000..56a477c --- /dev/null +++ b/detections/docs/unusual_http_method_used.md @@ -0,0 +1,18 @@ +## Overview + +Detect when a web server received requests using unusual or potentially dangerous HTTP methods. While common HTTP methods like GET, POST, and HEAD are expected in normal web traffic, other methods such as PUT, DELETE, CONNECT, and TRACE can sometimes indicate reconnaissance, vulnerability scanning, or active exploitation attempts. Many of these less common methods have legitimate uses in REST APIs and WebDAV services, but they can also be misused to upload malicious content, delete resources, or gather information about the web server. + +The detection identifies requests using potentially dangerous HTTP methods, including: +- Methods that can modify server resources (PUT, DELETE, PATCH) +- Methods that can be used for reconnaissance (OPTIONS, TRACE) +- WebDAV-specific methods (PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK) +- Less common methods that may be used in attacks (DEBUG, TRACK, SEARCH) + +Unusual HTTP methods may indicate attempts to exploit vulnerabilities, gather information about the web server, or manipulate server resources without proper authorization. + +**References**: +- [MITRE ATT&CK: Collection (T1213)](https://attack.mitre.org/techniques/T1213/) +- [OWASP HTTP Methods](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/02-Configuration_and_Deployment_Management_Testing/06-Test_HTTP_Methods) +- [CWE-650: Trusting HTTP Permission Methods on the Server Side](https://cwe.mitre.org/data/definitions/650.html) +- [RFC 7231: Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content](https://tools.ietf.org/html/rfc7231) +- [Apache HTTP Server: Method Limiting Configuration](https://httpd.apache.org/docs/2.4/mod/mod_allowmethods.html) \ No newline at end of file diff --git a/detections/docs/unusual_traffic_spike_detected.md b/detections/docs/unusual_traffic_spike_detected.md new file mode 100644 index 0000000..bd94f80 --- /dev/null +++ b/detections/docs/unusual_traffic_spike_detected.md @@ -0,0 +1,25 @@ +## Overview + +Detect when a web server experienced unusual spikes in traffic volume compared to historical patterns. While traffic fluctuations are normal, sudden significant increases in request volume that deviate from established patterns can indicate various issues including viral content, misconfigured services, denial of service attacks, or other abnormal conditions. This detection compares current traffic levels to historical averages to identify anomalous patterns. + +The detection identifies traffic spikes by: +- Analyzing request volume over 5-minute intervals +- Comparing current traffic volume to a rolling historical average +- Identifying periods where traffic exceeds historical patterns by a significant threshold (100% increase) +- Filtering out normal fluctuations by requiring a minimum baseline of historical data + +Unusual traffic spikes may indicate: +- Distributed Denial of Service (DDoS) attacks +- Content that has "gone viral" unexpectedly +- Misconfigured applications causing excessive requests +- Broken client applications making repeated requests +- Scanning or enumeration activities + +Early detection of traffic anomalies allows organizations to investigate the cause and mitigate potential issues before they impact service availability or security. + +**References**: +- [MITRE ATT&CK: Network Denial of Service (T1498)](https://attack.mitre.org/techniques/T1498/) +- [MITRE ATT&CK: Service Exhaustion Flood (T1499.002)](https://attack.mitre.org/techniques/T1499/002/) +- [OWASP: Denial of Service](https://owasp.org/www-community/attacks/Denial_of_Service) +- [CWE-400: Uncontrolled Resource Consumption](https://cwe.mitre.org/data/definitions/400.html) +- [Apache HTTP Server: Performance Tuning](https://httpd.apache.org/docs/2.4/misc/perf-tuning.html) \ No newline at end of file diff --git a/detections/docs/very_slow_request_detected.md b/detections/docs/very_slow_request_detected.md new file mode 100644 index 0000000..b504b0b --- /dev/null +++ b/detections/docs/very_slow_request_detected.md @@ -0,0 +1,25 @@ +## Overview + +Detect when a web server processed HTTP requests with abnormally high response times. Excessively slow response times can indicate various issues including performance bottlenecks, resource contention, database problems, or potentially denial of service conditions. This detection identifies individual requests that exceed reasonable performance thresholds, which can help pinpoint specific problematic endpoints or transactions. + +The detection focuses on identifying HTTP requests where: +- The response time exceeds a significant threshold (5 seconds) +- Individual requests show extreme latency, regardless of the overall system performance +- Specific transactions are experiencing performance degradation + +Very slow requests may indicate: +- Inefficient code or database queries +- Resource contention issues (CPU, memory, disk I/O) +- External service dependencies that are slow or unresponsive +- DoS conditions targeting specific application functionality +- Misconfiguration in specific application components +- Network latency or connectivity issues + +Identifying these outlier requests helps teams address performance bottlenecks and potential availability issues before they impact larger portions of the application. + +**References**: +- [MITRE ATT&CK: Application Exhaustion Flood (T1499.003)](https://attack.mitre.org/techniques/T1499/003/) +- [OWASP: Denial of Service](https://owasp.org/www-community/attacks/Denial_of_Service) +- [CWE-400: Uncontrolled Resource Consumption](https://cwe.mitre.org/data/definitions/400.html) +- [Web Performance Best Practices](https://web.dev/performance-get-started/) +- [Apache mod_reqtimeout: Request Timeout Configuration](https://httpd.apache.org/docs/2.4/mod/mod_reqtimeout.html) \ No newline at end of file diff --git a/detections/docs/web_shell_access_attempted.md b/detections/docs/web_shell_access_attempted.md new file mode 100644 index 0000000..19342e5 --- /dev/null +++ b/detections/docs/web_shell_access_attempted.md @@ -0,0 +1,19 @@ +## Overview + +Detect when a web server received potential web shell upload or access attempts. Web shells are malicious scripts uploaded to a web server that provide an attacker with a convenient interface to remotely access and control the compromised server. Once uploaded, web shells can be used for a variety of malicious activities including file manipulation, credential theft, lateral movement, and launching additional attacks from the compromised server. + +The detection identifies patterns associated with web shell access and uploads, including: +- Requests to common web shell file extensions (.php, .jsp, .asp, .aspx, .cfm) +- Requests containing known web shell indicators in the URL (shell, cmd, command) +- Access to known web shell variants (c99, r57) +- Suspicious combinations of methods (POST/PUT) and URL patterns +- Successful responses to potentially malicious requests + +Web shells represent a significant security risk as they provide attackers with persistent access to compromised systems and can be used as a staging point for further attacks within the network. + +**References**: +- [MITRE ATT&CK: Web Shell (T1505.003)](https://attack.mitre.org/techniques/T1505/003/) +- [CISA Web Shell Malware Alert](https://www.cisa.gov/news-events/alerts/2021/04/15/nsa-cisa-joint-advisory-detecting-and-preventing-web-shell-malware) +- [Understanding Web Shells](https://owasp.org/www-community/attacks/Web_Shell) +- [CWE-434: Unrestricted Upload of File with Dangerous Type](https://cwe.mitre.org/data/definitions/434.html) +- [Apache Security: Preventing Unauthorized Access](https://httpd.apache.org/docs/2.4/misc/security_tips.html#serverroot) \ No newline at end of file diff --git a/detections/docs/xss_attempted.md b/detections/docs/xss_attempted.md new file mode 100644 index 0000000..cffad65 --- /dev/null +++ b/detections/docs/xss_attempted.md @@ -0,0 +1,19 @@ +## Overview + +Detect when a web server was targeted by cross-site scripting (XSS) attacks. Cross-Site Scripting is a type of security vulnerability typically found in web applications that allows attackers to inject client-side scripts into web pages viewed by other users. XSS enables attackers to bypass same-origin policy, allowing them to steal sensitive information like session tokens and cookies, or to perform actions impersonating the victim, potentially leading to account takeover or data theft. + +The detection identifies common XSS attack patterns in URL requests, including: +- Script tag injection attempts (`` when rendered by the browser. Similarly, Base64 encoding can be used to completely obscure the contents of a payload until it's decoded and executed. + +By examining both request URIs and User-Agent headers, this detection can identify attackers who attempt to evade security controls by hiding their encoded payloads in HTTP headers rather than request parameters. This comprehensive approach helps security teams identify sophisticated XSS attempts that specifically aim to bypass traditional security controls through encoding techniques. + +**References**: +- [OWASP XSS Filter Evasion Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/XSS_Filter_Evasion_Cheat_Sheet.html) +- [CWE-79: Improper Neutralization of Input During Web Page Generation](https://cwe.mitre.org/data/definitions/79.html) +- [OWASP Top 10 2021: A03 Injection](https://owasp.org/Top10/A03_2021-Injection/) +- [MITRE ATT&CK: T1059.007 Command and Scripting Interpreter: JavaScript](https://attack.mitre.org/techniques/T1059/007/) \ No newline at end of file diff --git a/detections/docs/xss_event_handler.md b/detections/docs/xss_event_handler.md new file mode 100644 index 0000000..7608716 --- /dev/null +++ b/detections/docs/xss_event_handler.md @@ -0,0 +1,17 @@ +## Overview + +The XSS Event Handler Attack detection identifies Cross-Site Scripting (XSS) attacks that specifically target HTML event handlers to execute malicious JavaScript. Event handlers like `onload`, `onerror`, and `onclick` can be injected into HTML elements to trigger JavaScript execution when certain browser events occur. + +This detection examines both HTTP requests and User-Agent headers for patterns indicating event handler-based XSS attempts. It focuses on identifying both common event handlers that are frequently targeted in XSS attacks and less common event handlers that may be used to evade basic security filters. + +Event handler XSS attacks are particularly dangerous because they can bypass traditional XSS filters that focus primarily on script tags. Attackers can inject these event handlers into various HTML elements, creating multiple attack vectors. For example, an attacker might inject `` into a comment field, causing the malicious JavaScript to execute when the image fails to load. + +Modern web applications have numerous event handlers available, and new ones are introduced with each HTML5 specification update. This detection looks for patterns indicating attempts to exploit these event handlers in both request URIs and User-Agent headers, allowing it to catch attackers who attempt to evade detection by hiding their payloads in HTTP headers rather than request parameters. + +By monitoring for these event handler patterns, security teams can identify both reconnaissance activities and active exploitation attempts targeting their web applications through this specific XSS vector. + +**References**: +- [OWASP XSS Filter Evasion Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/XSS_Filter_Evasion_Cheat_Sheet.html) +- [CWE-79: Improper Neutralization of Input During Web Page Generation](https://cwe.mitre.org/data/definitions/79.html) +- [OWASP Top 10 2021: A03 Injection](https://owasp.org/Top10/A03_2021-Injection/) +- [MITRE ATT&CK: T1059.007 Command and Scripting Interpreter: JavaScript](https://attack.mitre.org/techniques/T1059/007/) \ No newline at end of file diff --git a/detections/docs/xss_html_injection.md b/detections/docs/xss_html_injection.md new file mode 100644 index 0000000..26520ea --- /dev/null +++ b/detections/docs/xss_html_injection.md @@ -0,0 +1,17 @@ +## Overview + +The XSS HTML Injection detection identifies Cross-Site Scripting (XSS) attacks that use HTML tag injection to execute malicious JavaScript. Unlike direct script tag injection, this attack vector leverages various HTML elements with event handlers or specific attributes that can execute JavaScript code. + +This detection examines both HTTP requests and User-Agent headers for HTML elements commonly used in XSS attacks, including `