682bd69cf8
QA scan found 4 library files with functions that weren't exported, making them unavailable in subshells and nested calls. Added export statements for: - lib/attack-signatures.sh: 3 functions - lib/http-attack-analyzer.sh: 5 functions - lib/email-functions.sh: 18 functions - lib/rate-anomaly-detector.sh: 9 functions Total: 35 functions now properly exported This ensures functions are available when libraries are sourced by scripts that spawn subshells or use process substitution.
319 lines
14 KiB
Bash
319 lines
14 KiB
Bash
#!/bin/bash
|
|
#
|
|
# Attack Signature Database
|
|
# Extracted from Emerging Threats Open Ruleset (BSD License)
|
|
# Source: https://rules.emergingthreats.net/
|
|
#
|
|
# Copyright (c) 2003-2025, Emerging Threats
|
|
# All rights reserved.
|
|
# Redistribution and use permitted under BSD license terms.
|
|
#
|
|
# This file contains attack pattern signatures for detecting web-based attacks
|
|
# in HTTP access logs. Patterns are extracted and adapted from ET Open rules.
|
|
|
|
# Initialize associative arrays for attack patterns
|
|
declare -A ATTACK_SQLI # SQL Injection patterns
|
|
declare -A ATTACK_XSS # Cross-Site Scripting
|
|
declare -A ATTACK_CMD # Command Injection
|
|
declare -A ATTACK_TRAVERSAL # Path Traversal
|
|
declare -A ATTACK_INCLUSION # File Inclusion (LFI/RFI)
|
|
declare -A ATTACK_WEBSHELL # Webshell detection
|
|
declare -A ATTACK_CVE # Known CVE exploits
|
|
declare -A ATTACK_UPLOAD # File upload attacks
|
|
|
|
# Pattern format: [category_name]="regex_pattern||severity||||description"
|
|
# Severity: 1-100 (higher = more dangerous)
|
|
# Note: Using || as delimiter to allow | in regex patterns
|
|
|
|
# ============================================================================
|
|
# SQL INJECTION PATTERNS (extracted from emerging-sql.rules)
|
|
# ============================================================================
|
|
|
|
# UNION-based SQL injection
|
|
ATTACK_SQLI["union_select"]="union.*select|union.*all.*select||90||UNION SELECT injection"
|
|
ATTACK_SQLI["union_from"]="union.*from|union.*all.*from||90||UNION FROM injection"
|
|
|
|
# Basic SQL injection attempts
|
|
ATTACK_SQLI["basic_sqli"]="' or '1'='1|' or 1=1--|';--||85||Basic SQL injection"
|
|
ATTACK_SQLI["basic_sqli2"]="\" or \"1\"=\"1|\" or 1=1--||85||Basic SQL injection (double quotes)"
|
|
ATTACK_SQLI["comment_bypass"]="--[[:space:]]|#[[:space:]]|/\*|\*/||75||SQL comment injection"
|
|
|
|
# Blind SQL injection
|
|
ATTACK_SQLI["blind_sqli"]="sleep\(|benchmark\(|waitfor.*delay||80||Blind SQL injection"
|
|
ATTACK_SQLI["time_based"]="pg_sleep\(|dbms_lock\.sleep||85||Time-based blind SQLi"
|
|
|
|
# Stacked queries
|
|
ATTACK_SQLI["stacked_query"]="';.*drop|';.*insert|';.*delete|';.*update||90||Stacked query injection"
|
|
ATTACK_SQLI["stacked_exec"]="';.*exec|';.*execute||85||Stacked execution injection"
|
|
|
|
# SQL functions abuse
|
|
ATTACK_SQLI["sqli_functions"]="concat\(|group_concat\(|load_file\(|into.*outfile||85||SQL function abuse"
|
|
ATTACK_SQLI["sqli_info"]="information_schema|mysql\.user|sys\.databases||90||Database metadata access"
|
|
|
|
# Boolean-based injection
|
|
ATTACK_SQLI["sqli_operators"]="and.*1=1|or.*1=1|xor.*1=1||70||Boolean-based injection"
|
|
ATTACK_SQLI["sqli_boolean"]="and.*true|or.*false|and.*null||80||Boolean logic injection"
|
|
|
|
# Encoded SQL injection
|
|
ATTACK_SQLI["sqli_hex"]="0x[0-9a-f]{8,}|char\(|ascii\(||75||Hex-encoded injection"
|
|
ATTACK_SQLI["sqli_encoded"]="%27%20or%20|%27%20union%20|%22%20or%20||80||URL-encoded SQL injection"
|
|
|
|
# ============================================================================
|
|
# CROSS-SITE SCRIPTING (XSS) PATTERNS (from emerging-web_server.rules)
|
|
# ============================================================================
|
|
|
|
# Script tag injection
|
|
ATTACK_XSS["script_tag"]="<script|</script>|<SCRIPT|</SCRIPT>||80||Script tag injection"
|
|
ATTACK_XSS["script_src"]="<script.*src=|<SCRIPT.*SRC=||85||External script injection"
|
|
|
|
# JavaScript protocol handlers
|
|
ATTACK_XSS["javascript_proto"]="javascript:|javascript%3a||75||JavaScript protocol handler"
|
|
ATTACK_XSS["vbscript_proto"]="vbscript:|vbscript%3a||75||VBScript protocol handler"
|
|
|
|
# Event handler injection
|
|
ATTACK_XSS["event_handler"]="onerror=|onload=|onclick=|onmouseover=||85||Event handler injection"
|
|
ATTACK_XSS["event_handler2"]="onmouseout=|onfocus=|onblur=|onchange=||80||Event handler injection"
|
|
ATTACK_XSS["event_handler3"]="onsubmit=|onkeydown=|onkeyup=|onkeypress=||80||Keyboard event injection"
|
|
|
|
# Encoded script tags
|
|
ATTACK_XSS["encoded_script"]="%3Cscript|%3C%2Fscript|%3C%73%63%72%69%70%74||80||URL-encoded script tag"
|
|
ATTACK_XSS["double_encoded"]="%253Cscript|%253C%252Fscript||85||Double-encoded script tag"
|
|
|
|
# IFrame injection
|
|
ATTACK_XSS["iframe_injection"]="<iframe|</iframe>|<IFRAME||75||IFrame injection"
|
|
ATTACK_XSS["iframe_src"]="<iframe.*src=|<IFRAME.*SRC=||80||External IFrame injection"
|
|
|
|
# Image-based XSS
|
|
ATTACK_XSS["img_onerror"]="<img.*onerror|<IMG.*onerror||85||Image tag with onerror"
|
|
ATTACK_XSS["img_javascript"]="<img.*javascript:|<IMG.*javascript:||85||Image with JavaScript"
|
|
|
|
# SVG-based XSS
|
|
ATTACK_XSS["svg_injection"]="<svg.*onload|<SVG.*onload||80||SVG-based XSS"
|
|
ATTACK_XSS["svg_script"]="<svg.*<script|<SVG.*<SCRIPT||85||SVG with embedded script"
|
|
|
|
# Data URI injection
|
|
ATTACK_XSS["data_uri"]="data:text/html|data:text/javascript||70||Data URI injection"
|
|
ATTACK_XSS["data_base64"]="data:.*base64||70||Base64 data URI injection"
|
|
|
|
# ============================================================================
|
|
# COMMAND INJECTION PATTERNS
|
|
# ============================================================================
|
|
|
|
# Basic command injection
|
|
ATTACK_CMD["basic_cmd"]="cmd=|exec=|system=|shell=|command=||85||Command parameter injection"
|
|
ATTACK_CMD["execute"]="execute=|run=|process=||90||Execute parameter injection"
|
|
|
|
# Unix command chaining
|
|
ATTACK_CMD["unix_cmd"]=";cat |;ls |;wget |;curl |;nc ||90||Unix command chaining"
|
|
ATTACK_CMD["unix_cmd2"]=";bash |;sh |;id |;whoami |;uname ||90||Unix shell commands"
|
|
ATTACK_CMD["unix_read"]=";head |;tail |;more |;less |;cat ||85||Unix file read commands"
|
|
|
|
# Windows command injection
|
|
ATTACK_CMD["windows_cmd"]="cmd\.exe|powershell|net\.exe|taskkill||85||Windows command injection"
|
|
ATTACK_CMD["windows_ps"]="powershell\.exe|pwsh|Start-Process||90||PowerShell injection"
|
|
|
|
# Command chaining operators
|
|
ATTACK_CMD["pipe_redirect"]="\||&&|\`|\\$\\(||90||Command chaining operators"
|
|
ATTACK_CMD["redirect"]=">[[:space:]]|>>[[:space:]]|<[[:space:]]||80||Shell redirection"
|
|
|
|
# Encoded commands
|
|
ATTACK_CMD["base64_cmd"]="echo.*\|.*base64|base64.*-d||75||Base64-encoded commands"
|
|
ATTACK_CMD["hex_cmd"]="\\x[0-9a-f]{2}||70||Hex-encoded commands"
|
|
|
|
# ============================================================================
|
|
# PATH TRAVERSAL PATTERNS
|
|
# ============================================================================
|
|
|
|
# Directory traversal
|
|
ATTACK_TRAVERSAL["dotdot"]="\\.\\./|\\.\\.|%2e%2e|%252e%252e||80||Directory traversal"
|
|
ATTACK_TRAVERSAL["dotdot_encoded"]="%%32%65|%%32%45|%c0%ae||85||Encoded directory traversal"
|
|
|
|
# Sensitive file access
|
|
ATTACK_TRAVERSAL["passwd"]="/etc/passwd|/etc/shadow|/etc/hosts||90||Unix password file access"
|
|
ATTACK_TRAVERSAL["windows_sys"]="c:\\\\windows\\\\|c:\\\\winnt\\\\|\\\\windows\\\\system32||85||Windows system file access"
|
|
ATTACK_TRAVERSAL["config_files"]="/etc/apache|/etc/nginx|/etc/mysql|httpd\.conf||85||Configuration file access"
|
|
|
|
# Double encoding
|
|
ATTACK_TRAVERSAL["double_encode"]="%252e%252e%252f|%c0%ae%c0%ae||85||Double-encoded traversal"
|
|
|
|
# Null byte injection
|
|
ATTACK_TRAVERSAL["null_byte"]="%00|\\0|\\x00||70||Null byte injection"
|
|
|
|
# ============================================================================
|
|
# FILE INCLUSION PATTERNS
|
|
# ============================================================================
|
|
|
|
# PHP wrapper abuse
|
|
ATTACK_INCLUSION["php_wrapper"]="php://filter|php://input|php://output||85||PHP filter wrapper"
|
|
ATTACK_INCLUSION["lfi_wrapper"]="file://|data://|expect://|zip://||85||Local file inclusion wrapper"
|
|
ATTACK_INCLUSION["phar_wrapper"]="phar://|rar://|ogg://||80||Archive wrapper abuse"
|
|
|
|
# Remote file inclusion
|
|
ATTACK_INCLUSION["rfi_http"]="http://.*\\.txt|https://.*\\.txt|ftp://.*\\.txt||90||Remote file inclusion"
|
|
ATTACK_INCLUSION["rfi_param"]="include=http|require=http|page=http||90||RFI via HTTP parameter"
|
|
|
|
# Log poisoning
|
|
ATTACK_INCLUSION["lfi_log"]="/var/log/apache|/var/log/nginx|access\.log|error\.log||80||Log file poisoning"
|
|
ATTACK_INCLUSION["lfi_proc"]="/proc/self/environ|/proc/self/fd||85||Process file inclusion"
|
|
|
|
# ============================================================================
|
|
# WEBSHELL PATTERNS (from emerging-web_server.rules)
|
|
# ============================================================================
|
|
|
|
# Known webshells
|
|
ATTACK_WEBSHELL["known_shells"]="c99\\.php|r57\\.php|b374k|wso\\.php||95||Known webshell filename"
|
|
ATTACK_WEBSHELL["known_shells2"]="shell\\.php|cmd\\.php|backdoor\\.php|webshell\\.php||95||Generic webshell filename"
|
|
ATTACK_WEBSHELL["china_shells"]="caidao|chopper|godzilla|behinder||95||Chinese webshell"
|
|
ATTACK_WEBSHELL["alfa_shell"]="alfa|alfanew|alfa-rex|alfacgiapi||95||Alfa Team webshell"
|
|
ATTACK_WEBSHELL["common_shells"]="mini\\.php|phpspy|antichat|idx|indoxploit||95||Common webshells"
|
|
ATTACK_WEBSHELL["suspicious_php"]="admin\\.php|wp-config\\.php|configuration\\.php.*\\?|index\\.php\\?||85||Suspicious PHP in wrong location"
|
|
|
|
# Upload script abuse
|
|
ATTACK_WEBSHELL["upload_shell"]="upload\\.php|uploader\\.php|file_upload\\.php||85||Upload script abuse"
|
|
ATTACK_WEBSHELL["filemanager"]="filemanager\\.php|elfinder|tinymce.*upload||80||File manager abuse"
|
|
|
|
# Obfuscated code patterns
|
|
ATTACK_WEBSHELL["obfuscated"]="eval\\(|base64_decode\\(|gzinflate\\(|str_rot13\\(||90||Obfuscated PHP code"
|
|
ATTACK_WEBSHELL["obfuscated2"]="assert\\(|preg_replace.*\\/e|create_function\\(||90||Dangerous PHP functions"
|
|
|
|
# Backdoor patterns
|
|
ATTACK_WEBSHELL["backdoor"]="backdoor|rootkit|c99shell|r57shell||95||Backdoor keywords"
|
|
ATTACK_WEBSHELL["webshell_param"]="cmd=|command=|exec=|passthru=||90||Webshell command parameter"
|
|
|
|
# ============================================================================
|
|
# KNOWN CVE EXPLOIT PATTERNS
|
|
# ============================================================================
|
|
|
|
# Critical CVEs
|
|
ATTACK_CVE["log4shell"]="jndi:ldap://|jndi:rmi://|jndi:dns://|jndi:nis://||95||CVE-2021-44228 Log4Shell"
|
|
ATTACK_CVE["shellshock"]="\\(\\) \\{ :;\\};|bash -c |/bin/bash -c||95||CVE-2014-6271 Shellshock"
|
|
ATTACK_CVE["struts2"]="Content-Type:.*ognl|%\\{|#_memberAccess||90||CVE-2017-5638 Struts2"
|
|
ATTACK_CVE["spring4shell"]="class\\.module\\.classLoader|accessLogValve||90||CVE-2022-22965 Spring4Shell"
|
|
|
|
# High severity CVEs
|
|
ATTACK_CVE["php_cgi"]="\\?-d allow_url_include|\\?-d auto_prepend||85||CVE-2012-1823 PHP-CGI"
|
|
ATTACK_CVE["struts2_s2057"]="\\.(action|do).*%\\{||85||CVE-2018-11776 Struts2 S2-057"
|
|
ATTACK_CVE["bluekeep"]="MS_T120|3389||85||CVE-2019-0708 BlueKeep"
|
|
ATTACK_CVE["proxylogon"]="/owa/auth/.*autodiscover|/ecp/.*proxyLogon||90||CVE-2021-26855 ProxyLogon"
|
|
|
|
# Medium severity CVEs
|
|
ATTACK_CVE["drupalgeddon"]="drupalgeddon|node/\\?||70||CVE-2018-7600 Drupal RCE"
|
|
ATTACK_CVE["citrix_traversal"]="vpns.*\\.\\..*\\.xml||75||CVE-2019-19781 Citrix ADC"
|
|
ATTACK_CVE["f5_bigip"]="tmui.*\\.\\..*hsqldb||80||CVE-2020-5902 F5 BIG-IP"
|
|
ATTACK_CVE["phpunit"]="\\.\\..*web-console|vendor/phpunit||70||CVE-2017-9841 PHPUnit"
|
|
|
|
# ============================================================================
|
|
# FILE UPLOAD ATTACK PATTERNS
|
|
# ============================================================================
|
|
|
|
# Double extension bypass
|
|
ATTACK_UPLOAD["double_ext"]="\\.php\\.jpg|\\.php\\.png|\\.php\\.gif|\\.phtml||80||Double extension upload"
|
|
ATTACK_UPLOAD["double_ext2"]="\\.php5|\\.php7|\\.pht|\\.phps||80||PHP alternative extension"
|
|
|
|
# MIME type mismatch
|
|
ATTACK_UPLOAD["mime_mismatch"]="Content-Type:.*application/x-php||85||MIME type mismatch"
|
|
ATTACK_UPLOAD["mime_bypass"]="Content-Type:.*text/php||80||PHP MIME type"
|
|
|
|
# Null byte upload bypass
|
|
ATTACK_UPLOAD["null_byte_upload"]="\\.php%00\\.jpg|\\.php\\\\0\\.png||90||Null byte upload bypass"
|
|
|
|
# Dangerous file types
|
|
ATTACK_UPLOAD["dangerous_ext"]="\\.exe|\\.bat|\\.cmd|\\.vbs|\\.ps1||85||Dangerous executable upload"
|
|
ATTACK_UPLOAD["script_upload"]="\\.sh|\\.pl|\\.py|\\.rb||80||Script file upload"
|
|
|
|
# ============================================================================
|
|
# HELPER FUNCTIONS
|
|
# ============================================================================
|
|
|
|
# Check if request matches attack pattern in specific category
|
|
# Usage: check_attack_pattern "$request_line" "ATTACK_SQLI"
|
|
# Returns: severity|pattern_name|description or empty string
|
|
check_attack_pattern() {
|
|
local request="$1"
|
|
local category="$2"
|
|
|
|
# Get reference to the associative array
|
|
local -n patterns="$category"
|
|
|
|
for pattern_name in "${!patterns[@]}"; do
|
|
local pattern_data="${patterns[$pattern_name]}"
|
|
|
|
# Parse pattern data: regex||severity||description
|
|
local regex="${pattern_data%%||*}"
|
|
local temp="${pattern_data#*||}"
|
|
local severity="${temp%%||*}"
|
|
local description="${temp#*||}"
|
|
|
|
# Case-insensitive regex match
|
|
if echo "$request" | grep -iEq "$regex" 2>/dev/null; then
|
|
echo "$severity||$pattern_name||$description"
|
|
return 0
|
|
fi
|
|
done
|
|
|
|
return 1
|
|
}
|
|
|
|
# Get all matching patterns across all categories
|
|
# Usage: detect_all_attack_signatures "$request_line"
|
|
# Returns: max_severity|match_count|matches (space-separated)
|
|
# Each match format: severity|category|pattern_name|description
|
|
# Note: Renamed to avoid conflict with legacy detect_all_attacks in attack-patterns.sh
|
|
detect_all_attack_signatures() {
|
|
local request="$1"
|
|
local matches=()
|
|
local max_severity=0
|
|
|
|
# Check all categories
|
|
local categories=("ATTACK_SQLI" "ATTACK_XSS" "ATTACK_CMD" "ATTACK_TRAVERSAL"
|
|
"ATTACK_INCLUSION" "ATTACK_WEBSHELL" "ATTACK_CVE" "ATTACK_UPLOAD")
|
|
|
|
for category in "${categories[@]}"; do
|
|
local result=$(check_attack_pattern "$request" "$category")
|
|
if [ -n "$result" ]; then
|
|
local severity="${result%%||*}"
|
|
local temp="${result#*||}"
|
|
local pattern_name="${temp%%||*}"
|
|
local description="${temp#*||}"
|
|
|
|
# Format: severity||category||pattern_name||description
|
|
matches+=("$severity||${category#ATTACK_}||$pattern_name||$description")
|
|
|
|
# Track max severity (with validation)
|
|
if [[ "$severity" =~ ^[0-9]+$ ]] && [ "$severity" -gt "$max_severity" ]; then
|
|
max_severity="$severity"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
# Return results
|
|
if [ ${#matches[@]} -gt 0 ]; then
|
|
echo "$max_severity||${#matches[@]}||${matches[*]}"
|
|
return 0
|
|
fi
|
|
|
|
return 1
|
|
}
|
|
|
|
# Get attack category name (human-readable)
|
|
get_category_name() {
|
|
local category="$1"
|
|
|
|
case "$category" in
|
|
SQLI) echo "SQL Injection" ;;
|
|
XSS) echo "Cross-Site Scripting" ;;
|
|
CMD) echo "Command Injection" ;;
|
|
TRAVERSAL) echo "Path Traversal" ;;
|
|
INCLUSION) echo "File Inclusion" ;;
|
|
WEBSHELL) echo "Webshell" ;;
|
|
CVE) echo "CVE Exploit" ;;
|
|
UPLOAD) echo "Malicious Upload" ;;
|
|
*) echo "$category" ;;
|
|
esac
|
|
}
|
|
|
|
# Export functions for use in subshells
|
|
export -f check_attack_pattern
|
|
export -f detect_all_attack_signatures
|
|
export -f get_category_name
|