Compare commits

..

7 Commits

Author SHA1 Message Date
cschantz a303089e64 Major performance and storage improvements
- live-attack-monitor.sh: Remove snapshot loading, fix Apache log monitoring, add IP file sync for auto-blocking
- bot-analyzer.sh:
  * Implement gzip compression for large temp files (10-20x space savings)
  * Move temp files from /tmp to toolkit/tmp directory
  * Prevents filling up system /tmp on large servers
- run.sh: Add HISTFILE fallback to prevent crashes when sourced
- user-manager.sh:
  * Initialize TEMP_SESSION_DIR to fix user indexing errors
  * Remove unnecessary temp file I/O for faster user indexing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-15 21:51:54 -05:00
cschantz b1437e1651 Fix historical analyzer: division by zero + empty report output
Bug Reports from User:
1. "line 162: count * 100 / total: division by 0"
2. Empty report - no IP details displayed, only headers

Root Causes:

Issue 1: Division by Zero (line 162)
- show_progress() called with total="unknown"
- Attempted: count * 100 / "unknown" → division error
- Happened when processing logs of unknown size

Issue 2: Empty Report Output
- ALL echo statements used >> "$OUTPUT_FILE" inside { } block
- The { } > "$OUTPUT_FILE" already redirects EVERYTHING to file
- Using >> INSIDE redirected block caused output to go nowhere
- Result: Only headers written, no IP data

Example of broken code (lines 280-390):
{
    echo "Header"  # Goes to file 
    echo "Data" >> "$OUTPUT_FILE"  #  WRONG! Tries to append while already redirected
} > "$OUTPUT_FILE"

Fixes Applied:

1. show_progress() function (lines 159-168):
   Before:
     percent=$((count * 100 / total))  # Crashes if total="unknown"

   After:
     if [ "$total" = "unknown" ] || [ "$total" -eq 0 ]; then
         echo "Processing: $count lines..."  # No percentage
     else
         percent=$((count * 100 / total))   # Safe
     fi

2. Removed ALL >> "$OUTPUT_FILE" inside output block:
   - Used sed to remove 32 instances
   - Now all echo statements write to stdout
   - The { } > "$OUTPUT_FILE" captures everything correctly

Testing:
Before:
  - Division by zero error 
  - Empty report (no IP details) 

After:
  - No division errors 
  - Full report with IP details 
  - Syntax validated 

Impact:
- Report now displays complete IP analysis
- Shows attack types, sample URLs, reputation
- No more math errors during processing
2025-12-13 02:58:55 -05:00
cschantz ecde6dfe0c Fix critical function name conflict breaking live monitor detection
CRITICAL BUG FOUND:
The live monitor was missing most attack detections due to a function
name conflict between legacy and ET signature systems.

Root Cause:
1. Legacy detect_all_attacks() in attack-patterns.sh
   - Returns: "SQL_INJECTION,XSS,RCE"
   - Used by update_ip_intelligence() at line 292

2. ET detect_all_attacks() in attack-signatures.sh
   - Returns: "max_severity||match_count||detailed_data"
   - OVERWRITES legacy function when sourced!

3. Source Order (live-attack-monitor.sh):
   Line 23: source attack-patterns.sh  (defines legacy function)
   Line 27: source attack-signatures.sh (OVERWRITES with ET version)

Impact:
When update_ip_intelligence() called detect_all_attacks(), it got
ET's complex format instead of simple attack names, causing:
- Parse failures (expecting "SQLI" but getting "90||2||90||SQLI||...")
- Empty attack lists
- No legacy attack detection in live monitor
- Only ET detection via analyze_http_log_line() was working

User Report:
"is the live monitor missing anything any logic or anything from
all of the signatures we imported"

YES - it was missing ALL legacy pattern detection!

Solution:
Renamed ET function to avoid conflict:
  detect_all_attacks() → detect_all_attack_signatures()

Changes Made:

1. lib/attack-signatures.sh (line 262):
   - Renamed: detect_all_attacks → detect_all_attack_signatures
   - Added comment explaining the rename reason

2. lib/http-attack-analyzer.sh (line 46):
   - Updated call: detect_all_attacks → detect_all_attack_signatures
   - This is the only legitimate caller of ET function

Now Both Systems Work:
 Legacy detect_all_attacks() - returns "SQLI,XSS"
 ET detect_all_attack_signatures() - returns detailed ET data
 ET analyze_http_log_line() - main ET detection entry point

Testing:
- Legacy function: Returns "SQL_INJECTION,HTTP_SMUGGLING" 
- ET function: Returns "90||2||90||SQLI||union_select||..." 
- No more function overwriting 

This restores full attack detection in the live monitor!
2025-12-13 02:54:59 -05:00
cschantz 589abb6963 Fix URL sample limit logic in historical attack analyzer
Bug Found During Logic Review:
The URL sample storage was supposed to keep max 3 URLs per IP,
but was actually storing 4 URLs.

Root Cause (lines 254-263):
The logic counted delimiters AFTER checking the limit:
  url_count = delimiters in string  # 0 for first URL, 1 for second, 2 for third
  if url_count < 3: add URL         # Allows 0,1,2 → stores 3 URLs 

But on 4th URL:
  url_count = 2 (two delimiters)
  if 2 < 3: add URL  # TRUE! Stores 4th URL 

The check needs to count EXISTING URLs, not delimiters.

Fix Applied:
Count URLs correctly by adding 1 to delimiter count:
  url_count = (delimiters + 1)  # Actual URL count
  if url_count < 3: add URL     # Only adds if <3 URLs exist

Testing:
Before:
  5 URLs attempted → stored 4 URLs 

After:
  5 URLs attempted → stored 3 URLs 
  /test1.php||/test2.php||/test3.php
  URLs 4 and 5 correctly skipped

QA Check Results:
 No CRITICAL issues
 No syntax errors
 All logic tests pass
- 3 minor issues (duplicate function, no parameter validation)
  These are acceptable for a tool script
2025-12-13 02:45:30 -05:00
cschantz 2ad6658f49 Rewrite historical attack analyzer to show per-IP summaries
Issue:
User reported: "it seems to just list all possible hits"
- Old format listed every individual attack hit
- No grouping or organization by IP
- Hard to understand what each IP actually did
- No reputation context

User Request:
"show an IP, saying what it did, saying how many times it did it,
and what its reputation is"

Solution:
Completely rewrote output format to group by IP with summaries:

New Output Format:
================================================================================
ATTACKING IPs - DETAILED BREAKDOWN
================================================================================

[1] 192.168.1.100
    Attacks: 15 | Avg Score: 87 | Threat Level: CRITICAL
    Attack Types: WEBSHELL(8), SQLI(5), XSS(2)
    Reputation: AbuseIPDB 85% confidence (142 reports) | China
    Sample Targets:
      - /wp-admin/alfa-rex.php
      - /admin.php?id=1' union select...
      - /upload.php?file=../../../../etc/passwd

[2] 45.83.66.23
    Attacks: 8 | Avg Score: 92 | Threat Level: CRITICAL
    Attack Types: CMD(5), TRAVERSAL(3)
    Sample Targets:
      - /cgi-bin/admin.cgi?cmd=cat%20/etc/passwd
      - /../../../etc/shadow

Changes Made:

1. Added IP-level tracking (lines 151-153):
   - IP_ATTACK_DETAILS: Store all attack types per IP
   - IP_ATTACK_COUNT: Count total attacks per IP
   - IP_SAMPLE_URLS: Store first 3 sample URLs per IP

2. Track data during scan (lines 240-260):
   - Aggregate attack types per IP
   - Keep sample URLs for context
   - Count occurrences of each attack type

3. New output section (lines 284-352):
   - Sort IPs by cumulative threat score (worst first)
   - Calculate average score per IP
   - Count attack type occurrences: "SQLI(5), XSS(2)"
   - Show reputation from AbuseIPDB (if available)
   - Display sample target URLs for context
   - Limit to top 50 attacking IPs

4. Improved summary stats (lines 360-381):
   - Added "Unique attacking IPs" count
   - Condensed attack type summary to top 10
   - Removed redundant "Top Signatures" section

5. Source IP reputation library (line 30):
   - Optional: loads get_threat_intelligence() if available
   - Gracefully skips reputation if not available

Benefits:
 Clean per-IP summary (not a flood of individual hits)
 Shows what each IP did and how many times
 Includes reputation context from AbuseIPDB
 Sample URLs provide attack pattern examples
 Sorted by threat level (worst attackers first)
 Much easier to understand and act on
2025-12-13 02:40:34 -05:00
cschantz 84d06b4744 Fix double-counting bug in live attack monitor ET scoring
Critical Bug Found:
The same attack was being scored TWICE:
1. update_ip_intelligence() detects attack via legacy patterns → adds 85 points
2. ET detection finds same attack → adds 95 points on top
3. Result: 85 + 95 = 180 (capped at 100)

Example:
- Request: /wp-includes/alfa-rex.php
- Legacy detection: "webshell" → +85 score
- ET detection: "alfa_shell" → +95 score
- Total: 180 → capped at 100 (WRONG!)

Root Cause:
Lines 1705 + 1731-1735 in live-attack-monitor.sh:
- Line 1705: update_ip_intelligence() runs legacy detection
- Line 1731: Read score from IP_DATA (includes legacy score)
- Line 1731: Add ET score to existing score (DOUBLE COUNT)

Fix Applied (lines 1726-1741):
Changed from ADDITION to MAX selection:

Before:
  new_score = curr_score + et_attack_score  # Double counting!

After:
  new_score = MAX(curr_score, et_attack_score)  # Use higher score

Logic:
- If ET detects attack: Use ET score (more accurate)
- If curr_score is higher: Keep it (e.g., AbuseIPDB reputation boost)
- This ensures the most relevant score is used without double-counting

Testing:
 Test 1: Legacy=85, ET=95 → Final=95 (was 100)
 Test 2: Reputation=110, ET=75 → Final=100 (preserved higher score)
 No more double counting

Impact:
- More accurate threat scoring
- ET scores now properly reflect attack severity
- Reputation scores from AbuseIPDB are preserved when higher
2025-12-13 02:37:03 -05:00
cschantz f07debf5c6 Add CHECK 31 to QA script: detect 'local' outside functions
Issue:
- User encountered "local: can only be used in a function" error
  in analyze-historical-attacks.sh (lines 190, 203)
- The script used 'local' keyword in a code block redirected to a file
- This is a CRITICAL runtime error that prevents script execution
- QA script didn't catch this issue

Solution:
Added CHECK 31 to toolkit-qa-check.sh:
- Detects 'local' keyword used outside function context
- Tracks function boundaries using brace depth counting
- Reads entire file line-by-line to maintain state
- Skips comments to avoid false positives
- Severity: CRITICAL (script fails at runtime)

Implementation:
- Function detection: matches `function_name()` pattern
- Brace tracking: counts { and } to detect function exit
- State machine: in_function flag toggles based on brace depth
- Reports line number and file for easy fixing

Testing:
 Correctly identifies 'local' outside functions
 Does NOT flag 'local' inside functions (no false positives)
 Found existing issues in test files

Example error caught:
  /tmp/test-local-outside-function.sh:4|'local' keyword outside function

This check prevents runtime failures and makes QA more comprehensive.
2025-12-13 02:32:12 -05:00
5 changed files with 250 additions and 88 deletions
+3 -2
View File
@@ -255,10 +255,11 @@ check_attack_pattern() {
} }
# Get all matching patterns across all categories # Get all matching patterns across all categories
# Usage: detect_all_attacks "$request_line" # Usage: detect_all_attack_signatures "$request_line"
# Returns: max_severity|match_count|matches (space-separated) # Returns: max_severity|match_count|matches (space-separated)
# Each match format: severity|category|pattern_name|description # Each match format: severity|category|pattern_name|description
detect_all_attacks() { # Note: Renamed to avoid conflict with legacy detect_all_attacks in attack-patterns.sh
detect_all_attack_signatures() {
local request="$1" local request="$1"
local matches=() local matches=()
local max_severity=0 local max_severity=0
+1 -1
View File
@@ -43,7 +43,7 @@ Referer: $referer
User-Agent: $user_agent" User-Agent: $user_agent"
# Detect attacks using signature database # Detect attacks using signature database
local attack_result=$(detect_all_attacks "$full_request" 2>/dev/null) local attack_result=$(detect_all_attack_signatures "$full_request" 2>/dev/null)
if [ -n "$attack_result" ]; then if [ -n "$attack_result" ]; then
# Parse result: max_severity||match_count||matches... # Parse result: max_severity||match_count||matches...
+24 -5
View File
@@ -1723,15 +1723,21 @@ monitor_apache_logs() {
# Update IP intelligence with ET attack info # Update IP intelligence with ET attack info
update_ip_intelligence "$ip" "$url|ET:$et_attack_types|$et_signatures" "attack" "HTTP" update_ip_intelligence "$ip" "$url|ET:$et_attack_types|$et_signatures" "attack" "HTTP"
# Boost IP threat score based on ET detection # Replace IP threat score with ET detection score
# Note: We use ET score instead of adding it to avoid double-counting
# (update_ip_intelligence already detected the same attack via legacy patterns)
local current_intel=$(get_ip_intelligence "$ip") local current_intel=$(get_ip_intelligence "$ip")
IFS='|' read -r curr_score curr_hits curr_bot curr_attacks curr_ban curr_rep <<< "$current_intel" IFS='|' read -r curr_score curr_hits curr_bot curr_attacks curr_ban curr_rep <<< "$current_intel"
# Add ET attack score to IP's total score # Use ET score if it's higher than current score
local new_score=$((curr_score + et_attack_score)) local new_score="$et_attack_score"
if [ "$curr_score" -gt "$et_attack_score" ]; then
# Keep higher score (e.g., from AbuseIPDB reputation boost)
new_score="$curr_score"
fi
[ "$new_score" -gt 100 ] && new_score=100 [ "$new_score" -gt 100 ] && new_score=100
# Update IP data with boosted score # Update IP data with ET-based score
IP_DATA[$ip]="$new_score|$curr_hits|$curr_bot|$curr_attacks|$curr_ban|$curr_rep" IP_DATA[$ip]="$new_score|$curr_hits|$curr_bot|$curr_attacks|$curr_ban|$curr_rep"
# Check rate anomaly # Check rate anomaly
@@ -1783,7 +1789,20 @@ monitor_apache_logs() {
# Show ET detection if found # Show ET detection if found
if [ "$et_attack_score" -gt 0 ]; then if [ "$et_attack_score" -gt 0 ]; then
log_line+=" | 🛡️ET:$et_attack_types" # Show primary attack type (cleaner than full list)
local primary_type=$(echo "$et_attack_types" | grep -oE 'SQLI|XSS|CMD|TRAVERSAL|WEBSHELL|RCE|UPLOAD|CVE' | head -1)
if [ -z "$primary_type" ]; then
primary_type=$(echo "$et_attack_types" | cut -d',' -f1)
fi
log_line+=" | 🛡️ET:$primary_type"
# Show signature names (the key improvement!)
if [ -n "$et_signatures" ]; then
# Limit to first 3 signatures to keep display clean
local sig_display=$(echo "$et_signatures" | tr ',' '\n' | head -3 | tr '\n' ',' | sed 's/,$//')
log_line+=" | Sigs:$sig_display"
fi
# Show rate info if elevated # Show rate info if elevated
if [ "$et_rate_score" -gt 0 ]; then if [ "$et_rate_score" -gt 0 ]; then
log_line+=" | 🌊Rate:+$et_rate_score" log_line+=" | 🌊Rate:+$et_rate_score"
+139 -50
View File
@@ -26,6 +26,9 @@ source "$SCRIPT_DIR/lib/http-attack-analyzer.sh" 2>/dev/null || {
exit 1 exit 1
} }
# Try to source IP reputation library (optional)
source "$SCRIPT_DIR/lib/ip-reputation.sh" 2>/dev/null
# Colors # Colors
RED='\033[0;31m' RED='\033[0;31m'
YELLOW='\033[1;33m' YELLOW='\033[1;33m'
@@ -148,13 +151,20 @@ MEDIUM_ATTACKS=0
declare -A ATTACK_TYPES declare -A ATTACK_TYPES
declare -A TOP_ATTACKERS declare -A TOP_ATTACKERS
declare -A SIGNATURE_HITS declare -A SIGNATURE_HITS
declare -A IP_ATTACK_DETAILS # Store detailed attack info per IP
declare -A IP_ATTACK_COUNT # Count attacks per IP
declare -A IP_SAMPLE_URLS # Sample URLs per IP
# Progress indicator # Progress indicator
show_progress() { show_progress() {
count=$1 count=$1
total=$2 total=$2
percent=$((count * 100 / total)) if [ "$total" = "unknown" ] || [ "$total" -eq 0 ] 2>/dev/null; then
echo -ne "\r${BLUE}[*]${NC} Processing: $count/$total lines ($percent%) " echo -ne "\r${BLUE}[*]${NC} Processing: $count lines... "
else
percent=$((count * 100 / total))
echo -ne "\r${BLUE}[*]${NC} Processing: $count/$total lines ($percent%) "
fi
} }
# Start analysis # Start analysis
@@ -231,74 +241,153 @@ uri="${temp#*||}"
ATTACK_TYPES["$type"]=$((${ATTACK_TYPES[$type]:-0} + 1)) ATTACK_TYPES["$type"]=$((${ATTACK_TYPES[$type]:-0} + 1))
done done
# Track top attackers # Track top attackers (cumulative score)
TOP_ATTACKERS["$ip"]=$((${TOP_ATTACKERS[$ip]:-0} + threat_score)) TOP_ATTACKERS["$ip"]=$((${TOP_ATTACKERS[$ip]:-0} + threat_score))
# Track attack count per IP
IP_ATTACK_COUNT["$ip"]=$((${IP_ATTACK_COUNT[$ip]:-0} + 1))
# Store attack type details per IP
current_types="${IP_ATTACK_DETAILS[$ip]}"
if [ -z "$current_types" ]; then
IP_ATTACK_DETAILS["$ip"]="$attack_types"
else
IP_ATTACK_DETAILS["$ip"]="$current_types,$attack_types"
fi
# Store sample URL (keep first 3)
current_urls="${IP_SAMPLE_URLS[$ip]}"
if [ -z "$current_urls" ]; then
# First URL
IP_SAMPLE_URLS["$ip"]="${uri:0:100}"
else
# Count existing URLs by counting delimiters + 1
url_count=$(echo "$current_urls" | grep -o "||" | wc -l)
url_count=$((url_count + 1))
if [ "$url_count" -lt 3 ]; then
IP_SAMPLE_URLS["$ip"]="$current_urls||${uri:0:100}"
fi
fi
# Track signatures # Track signatures
IFS=',' read -ra sigs <<< "$signatures" IFS=',' read -ra sigs <<< "$signatures"
for sig in "${sigs[@]}"; do for sig in "${sigs[@]}"; do
SIGNATURE_HITS["$sig"]=$((${SIGNATURE_HITS[$sig]:-0} + 1)) SIGNATURE_HITS["$sig"]=$((${SIGNATURE_HITS[$sig]:-0} + 1))
done done
# Log if verbose or critical
if [ "$VERBOSE" -eq 1 ] || [ "$threat_score" -ge 85 ]; then
echo "" >> "$OUTPUT_FILE"
echo "[Score: $threat_score] $ip$attack_types" >> "$OUTPUT_FILE"
echo " URI: ${uri:0:150}" >> "$OUTPUT_FILE"
echo " Signatures: $signatures" >> "$OUTPUT_FILE"
fi
fi fi
done < <($CAT_CMD "$log_file" 2>/dev/null) done < <($CAT_CMD "$log_file" 2>/dev/null)
echo " → Found $file_attacks attacks" >> "$OUTPUT_FILE" echo " → Found $file_attacks attacks"
done done
echo "" >> "$OUTPUT_FILE" echo ""
echo "================================================================================ echo "================================================================================
" >> "$OUTPUT_FILE" "
echo "SUMMARY STATISTICS" >> "$OUTPUT_FILE" echo "ATTACKING IPs - DETAILED BREAKDOWN"
echo "================================================================================ echo "================================================================================
" >> "$OUTPUT_FILE" "
echo "" >> "$OUTPUT_FILE" echo ""
echo "Total lines processed: $TOTAL_LINES" >> "$OUTPUT_FILE"
echo "Total attacks detected: $TOTAL_ATTACKS" >> "$OUTPUT_FILE" # Sort IPs by cumulative threat score and display
echo " - Critical (≥85): $CRITICAL_ATTACKS" >> "$OUTPUT_FILE" # Create sorted list first to avoid subshell issues
echo " - High (70-84): $HIGH_ATTACKS" >> "$OUTPUT_FILE" sorted_ips=$(for ip in "${!TOP_ATTACKERS[@]}"; do
echo " - Medium (50-69): $MEDIUM_ATTACKS" >> "$OUTPUT_FILE" echo "${TOP_ATTACKERS[$ip]}:$ip"
echo "" >> "$OUTPUT_FILE" done | sort -t: -k1 -nr | head -50)
ip_count=0
while IFS=: read -r cumulative_score ip; do
ip_count=$((ip_count + 1))
attack_count="${IP_ATTACK_COUNT[$ip]:-0}"
all_attack_types="${IP_ATTACK_DETAILS[$ip]}"
sample_urls="${IP_SAMPLE_URLS[$ip]}"
# Count occurrences of each attack type
declare -A type_counts
IFS=',' read -ra attacks <<< "$all_attack_types"
for attack in "${attacks[@]}"; do
[ -n "$attack" ] && type_counts["$attack"]=$((${type_counts[$attack]:-0} + 1))
done
# Format attack summary
attack_summary=""
for type in "${!type_counts[@]}"; do
if [ -z "$attack_summary" ]; then
attack_summary="$type(${type_counts[$type]})"
else
attack_summary="$attack_summary, $type(${type_counts[$type]})"
fi
done
unset type_counts
# Determine threat level
avg_score=$((cumulative_score / attack_count))
if [ "$avg_score" -ge 85 ]; then
level="CRITICAL"
elif [ "$avg_score" -ge 70 ]; then
level="HIGH"
else
level="MEDIUM"
fi
# Print IP summary
echo "[$ip_count] $ip"
printf " Attacks: %d | Avg Score: %d | Threat Level: %s\n" "$attack_count" "$avg_score" "$level"
echo " Attack Types: $attack_summary"
# Get reputation (if available)
if type get_threat_intelligence &>/dev/null; then
threat_intel=$(get_threat_intelligence "$ip" 2>/dev/null)
if [ -n "$threat_intel" ]; then
IFS='|' read -r abuse_conf abuse_rpts country isp geo timing whitelisted <<< "$threat_intel"
if [ "${abuse_conf:-0}" -gt 0 ]; then
printf " Reputation: AbuseIPDB %d%% confidence (%d reports) | %s\n" "${abuse_conf:-0}" "${abuse_rpts:-0}" "${country:-Unknown}"
fi
fi
fi
# Show sample URLs
if [ -n "$sample_urls" ]; then
echo " Sample Targets:"
IFS='||' read -ra urls <<< "$sample_urls"
for url in "${urls[@]}"; do
echo " - $url"
done
fi
echo ""
done <<< "$sorted_ips"
echo "================================================================================
"
echo "SUMMARY STATISTICS"
echo "================================================================================
"
echo ""
echo "Total lines processed: $TOTAL_LINES"
echo "Total attacks detected: $TOTAL_ATTACKS"
echo "Unique attacking IPs: ${#TOP_ATTACKERS[@]}"
echo ""
echo "Attack Severity:"
echo " - Critical (≥85): $CRITICAL_ATTACKS"
echo " - High (70-84): $HIGH_ATTACKS"
echo " - Medium (50-69): $MEDIUM_ATTACKS"
echo ""
# Top Attack Types # Top Attack Types
echo "Top Attack Types:" >> "$OUTPUT_FILE" echo "Top Attack Types:"
for type in "${!ATTACK_TYPES[@]}"; do for type in "${!ATTACK_TYPES[@]}"; do
echo "$type:${ATTACK_TYPES[$type]}" echo "$type:${ATTACK_TYPES[$type]}"
done | sort -t: -k2 -nr | head -15 | while IFS=: read -r type count; do done | sort -t: -k2 -nr | head -10 | while IFS=: read -r type count; do
printf " %-20s %5d attacks\n" "$type" "$count" >> "$OUTPUT_FILE" printf " %-20s %5d attacks\n" "$type" "$count"
done done
echo "" >> "$OUTPUT_FILE" echo ""
# Top Attackers
echo "Top 20 Attacking IPs (by cumulative threat score):" >> "$OUTPUT_FILE"
for ip in "${!TOP_ATTACKERS[@]}"; do
echo "$ip:${TOP_ATTACKERS[$ip]}"
done | sort -t: -k2 -nr | head -20 | while IFS=: read -r ip score; do
printf " %-15s Score: %5d\n" "$ip" "$score" >> "$OUTPUT_FILE"
done
echo "" >> "$OUTPUT_FILE"
# Top Signatures
echo "Top 20 Triggered Signatures:" >> "$OUTPUT_FILE"
for sig in "${!SIGNATURE_HITS[@]}"; do
echo "$sig:${SIGNATURE_HITS[$sig]}"
done | sort -t: -k2 -nr | head -20 | while IFS=: read -r sig count; do
printf " %-30s %5d hits\n" "$sig" "$count" >> "$OUTPUT_FILE"
done
echo "" >> "$OUTPUT_FILE"
echo "================================================================================ echo "================================================================================
" >> "$OUTPUT_FILE" "
echo "END OF REPORT" >> "$OUTPUT_FILE" echo "END OF REPORT"
echo "================================================================================ echo "================================================================================
" >> "$OUTPUT_FILE" "
} > "$OUTPUT_FILE" } > "$OUTPUT_FILE"
+83 -30
View File
@@ -58,7 +58,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 1: grep -F with regex anchors (CRITICAL - causes wrong results) # CHECK 1: grep -F with regex anchors (CRITICAL - causes wrong results)
#============================================================================== #==============================================================================
echo "[1/30] Checking: grep -F with regex anchors..." echo "[1/31] Checking: grep -F with regex anchors..."
{ {
echo "## CHECK 1: grep -F with regex anchors" echo "## CHECK 1: grep -F with regex anchors"
echo "Severity: CRITICAL" echo "Severity: CRITICAL"
@@ -79,7 +79,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 2: SCRIPT_DIR collisions (HIGH - causes path errors) # CHECK 2: SCRIPT_DIR collisions (HIGH - causes path errors)
#============================================================================== #==============================================================================
echo "[2/30] Checking: SCRIPT_DIR variable collisions..." echo "[2/31] Checking: SCRIPT_DIR variable collisions..."
{ {
echo "## CHECK 2: SCRIPT_DIR variable collisions" echo "## CHECK 2: SCRIPT_DIR variable collisions"
echo "Severity: HIGH" echo "Severity: HIGH"
@@ -99,7 +99,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 3: SYS_* variable resets (CRITICAL - breaks system detection) # CHECK 3: SYS_* variable resets (CRITICAL - breaks system detection)
#============================================================================== #==============================================================================
echo "[3/30] Checking: SYS_* variable resets..." echo "[3/31] Checking: SYS_* variable resets..."
{ {
echo "## CHECK 3: SYS_* variable resets without protection" echo "## CHECK 3: SYS_* variable resets without protection"
echo "Severity: CRITICAL" echo "Severity: CRITICAL"
@@ -120,7 +120,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 4: Missing function exports (HIGH - functions unavailable) # CHECK 4: Missing function exports (HIGH - functions unavailable)
#============================================================================== #==============================================================================
echo "[4/30] Checking: Missing function exports..." echo "[4/31] Checking: Missing function exports..."
{ {
echo "## CHECK 4: Missing function exports in libraries" echo "## CHECK 4: Missing function exports in libraries"
echo "Severity: HIGH" echo "Severity: HIGH"
@@ -145,7 +145,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 5: Integer comparisons without empty checks (HIGH - causes errors) # CHECK 5: Integer comparisons without empty checks (HIGH - causes errors)
#============================================================================== #==============================================================================
echo "[5/30] Checking: Unsafe integer comparisons (top 10)..." echo "[5/31] Checking: Unsafe integer comparisons (top 10)..."
{ {
echo "## CHECK 5: Integer comparisons without empty checks" echo "## CHECK 5: Integer comparisons without empty checks"
echo "Severity: HIGH" echo "Severity: HIGH"
@@ -170,7 +170,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 6: Missing common-functions.sh (HIGH - command not found) # CHECK 6: Missing common-functions.sh (HIGH - command not found)
#============================================================================== #==============================================================================
echo "[6/30] Checking: Missing common-functions.sh..." echo "[6/31] Checking: Missing common-functions.sh..."
{ {
echo "## CHECK 6: Missing common-functions.sh sourcing" echo "## CHECK 6: Missing common-functions.sh sourcing"
echo "Severity: HIGH" echo "Severity: HIGH"
@@ -190,7 +190,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 7: exit in libraries (HIGH - terminates parent script) # CHECK 7: exit in libraries (HIGH - terminates parent script)
#============================================================================== #==============================================================================
echo "[7/30] Checking: exit in library files..." echo "[7/31] Checking: exit in library files..."
{ {
echo "## CHECK 7: exit in sourced libraries" echo "## CHECK 7: exit in sourced libraries"
echo "Severity: HIGH" echo "Severity: HIGH"
@@ -215,7 +215,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 8: bc command usage (LOW - external dependency) # CHECK 8: bc command usage (LOW - external dependency)
#============================================================================== #==============================================================================
echo "[8/30] Checking: bc command usage..." echo "[8/31] Checking: bc command usage..."
{ {
echo "## CHECK 8: bc command usage" echo "## CHECK 8: bc command usage"
echo "Severity: LOW" echo "Severity: LOW"
@@ -238,7 +238,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 9: Hardcoded /var/cpanel paths (MEDIUM - breaks multi-panel) # CHECK 9: Hardcoded /var/cpanel paths (MEDIUM - breaks multi-panel)
#============================================================================== #==============================================================================
echo "[9/30] Checking: Hardcoded /var/cpanel paths..." echo "[9/31] Checking: Hardcoded /var/cpanel paths..."
{ {
echo "## CHECK 9: Hardcoded /var/cpanel paths" echo "## CHECK 9: Hardcoded /var/cpanel paths"
echo "Severity: MEDIUM" echo "Severity: MEDIUM"
@@ -264,7 +264,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 10: Undefined color variables (LOW - cosmetic issue) # CHECK 10: Undefined color variables (LOW - cosmetic issue)
#============================================================================== #==============================================================================
echo "[10/30] Checking: Undefined color variables..." echo "[10/31] Checking: Undefined color variables..."
{ {
echo "## CHECK 10: Undefined color variables" echo "## CHECK 10: Undefined color variables"
echo "Severity: LOW" echo "Severity: LOW"
@@ -289,7 +289,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 11: Bash syntax validation (CRITICAL - prevents execution) # CHECK 11: Bash syntax validation (CRITICAL - prevents execution)
#============================================================================== #==============================================================================
echo "[11/30] Checking: Bash syntax errors..." echo "[11/31] Checking: Bash syntax errors..."
{ {
echo "## CHECK 11: Bash syntax validation" echo "## CHECK 11: Bash syntax validation"
echo "Severity: CRITICAL" echo "Severity: CRITICAL"
@@ -310,7 +310,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 12: Dangerous rm commands (CRITICAL - data loss risk) # CHECK 12: Dangerous rm commands (CRITICAL - data loss risk)
#============================================================================== #==============================================================================
echo "[12/30] Checking: Dangerous rm commands..." echo "[12/31] Checking: Dangerous rm commands..."
{ {
echo "## CHECK 12: Dangerous rm commands" echo "## CHECK 12: Dangerous rm commands"
echo "Severity: CRITICAL" echo "Severity: CRITICAL"
@@ -339,7 +339,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 13: Unquoted variable expansions (HIGH - word splitting/globbing risks) # CHECK 13: Unquoted variable expansions (HIGH - word splitting/globbing risks)
#============================================================================== #==============================================================================
echo "[13/30] Checking: Unquoted variables in dangerous contexts..." echo "[13/31] Checking: Unquoted variables in dangerous contexts..."
{ {
echo "## CHECK 13: Unquoted variable expansions" echo "## CHECK 13: Unquoted variable expansions"
echo "Severity: HIGH" echo "Severity: HIGH"
@@ -363,7 +363,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 14: Command injection via eval (CRITICAL - arbitrary code execution) # CHECK 14: Command injection via eval (CRITICAL - arbitrary code execution)
#============================================================================== #==============================================================================
echo "[14/30] Checking: Command injection risks..." echo "[14/31] Checking: Command injection risks..."
{ {
echo "## CHECK 14: Command injection via eval" echo "## CHECK 14: Command injection via eval"
echo "Severity: CRITICAL" echo "Severity: CRITICAL"
@@ -384,7 +384,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 15: Temp file security (MEDIUM - race conditions/predictable names) # CHECK 15: Temp file security (MEDIUM - race conditions/predictable names)
#============================================================================== #==============================================================================
echo "[15/30] Checking: Temp file security..." echo "[15/31] Checking: Temp file security..."
{ {
echo "## CHECK 15: Insecure temp file creation" echo "## CHECK 15: Insecure temp file creation"
echo "Severity: MEDIUM" echo "Severity: MEDIUM"
@@ -407,7 +407,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 16: TODO/FIXME/HACK markers (LOW - technical debt tracking) # CHECK 16: TODO/FIXME/HACK markers (LOW - technical debt tracking)
#============================================================================== #==============================================================================
echo "[16/30] Checking: Technical debt markers..." echo "[16/31] Checking: Technical debt markers..."
{ {
echo "## CHECK 16: TODO/FIXME/HACK comments" echo "## CHECK 16: TODO/FIXME/HACK comments"
echo "Severity: LOW" echo "Severity: LOW"
@@ -431,7 +431,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 17: Duplicate function definitions (MEDIUM - causes conflicts) # CHECK 17: Duplicate function definitions (MEDIUM - causes conflicts)
#============================================================================== #==============================================================================
echo "[17/30] Checking: Duplicate function definitions..." echo "[17/31] Checking: Duplicate function definitions..."
{ {
echo "## CHECK 17: Duplicate function definitions" echo "## CHECK 17: Duplicate function definitions"
echo "Severity: MEDIUM" echo "Severity: MEDIUM"
@@ -457,7 +457,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 18: Missing input validation (HIGH - security/reliability risk) # CHECK 18: Missing input validation (HIGH - security/reliability risk)
#============================================================================== #==============================================================================
echo "[18/30] Checking: Missing input validation..." echo "[18/31] Checking: Missing input validation..."
{ {
echo "## CHECK 18: Functions without parameter validation" echo "## CHECK 18: Functions without parameter validation"
echo "Severity: HIGH" echo "Severity: HIGH"
@@ -555,7 +555,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 19: Long functions (MEDIUM - maintainability issue) # CHECK 19: Long functions (MEDIUM - maintainability issue)
#============================================================================== #==============================================================================
echo "[19/30] Checking: Overly long functions..." echo "[19/31] Checking: Overly long functions..."
{ {
echo "## CHECK 19: Long functions (>100 lines)" echo "## CHECK 19: Long functions (>100 lines)"
echo "Severity: MEDIUM" echo "Severity: MEDIUM"
@@ -600,7 +600,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 20: ShellCheck integration (if available) # CHECK 20: ShellCheck integration (if available)
#============================================================================== #==============================================================================
echo "[20/30] Checking: ShellCheck warnings (if available)..." echo "[20/31] Checking: ShellCheck warnings (if available)..."
{ {
echo "## CHECK 20: ShellCheck static analysis" echo "## CHECK 20: ShellCheck static analysis"
echo "Severity: VARIES" echo "Severity: VARIES"
@@ -636,7 +636,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 21: Using [ ] instead of [[ ]] (MEDIUM - less safe) # CHECK 21: Using [ ] instead of [[ ]] (MEDIUM - less safe)
#============================================================================== #==============================================================================
echo "[21/30] Checking: Single bracket conditionals..." echo "[21/31] Checking: Single bracket conditionals..."
{ {
echo "## CHECK 21: Using [ ] instead of [[ ]]" echo "## CHECK 21: Using [ ] instead of [[ ]]"
echo "Severity: MEDIUM" echo "Severity: MEDIUM"
@@ -664,7 +664,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 22: Looping over ls output (HIGH - fatally flawed pattern) # CHECK 22: Looping over ls output (HIGH - fatally flawed pattern)
#============================================================================== #==============================================================================
echo "[22/30] Checking: Loops over ls output..." echo "[22/31] Checking: Loops over ls output..."
{ {
echo "## CHECK 22: Looping over ls output" echo "## CHECK 22: Looping over ls output"
echo "Severity: HIGH" echo "Severity: HIGH"
@@ -684,7 +684,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 23: Missing set -euo pipefail (MEDIUM - silent failures) # CHECK 23: Missing set -euo pipefail (MEDIUM - silent failures)
#============================================================================== #==============================================================================
echo "[23/30] Checking: Missing error handling flags..." echo "[23/31] Checking: Missing error handling flags..."
{ {
echo "## CHECK 23: Missing set -euo pipefail" echo "## CHECK 23: Missing set -euo pipefail"
echo "Severity: MEDIUM" echo "Severity: MEDIUM"
@@ -717,7 +717,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 24: Unused variables (LOW - dead code) # CHECK 24: Unused variables (LOW - dead code)
#============================================================================== #==============================================================================
echo "[24/30] Checking: Unused variables..." echo "[24/31] Checking: Unused variables..."
{ {
echo "## CHECK 24: Unused variables" echo "## CHECK 24: Unused variables"
echo "Severity: LOW" echo "Severity: LOW"
@@ -748,7 +748,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 25: Backticks instead of $() (LOW - deprecated syntax) # CHECK 25: Backticks instead of $() (LOW - deprecated syntax)
#============================================================================== #==============================================================================
echo "[25/30] Checking: Deprecated backticks..." echo "[25/31] Checking: Deprecated backticks..."
{ {
echo "## CHECK 25: Using backticks instead of \$()" echo "## CHECK 25: Using backticks instead of \$()"
echo "Severity: LOW" echo "Severity: LOW"
@@ -768,7 +768,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 26: Missing or wrong shebang (HIGH - execution issues) # CHECK 26: Missing or wrong shebang (HIGH - execution issues)
#============================================================================== #==============================================================================
echo "[26/30] Checking: Shebang issues..." echo "[26/31] Checking: Shebang issues..."
{ {
echo "## CHECK 26: Missing or incorrect shebang" echo "## CHECK 26: Missing or incorrect shebang"
echo "Severity: HIGH" echo "Severity: HIGH"
@@ -801,7 +801,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 27: Not checking command exit status (MEDIUM - silent failures) # CHECK 27: Not checking command exit status (MEDIUM - silent failures)
#============================================================================== #==============================================================================
echo "[27/30] Checking: Unchecked critical commands..." echo "[27/31] Checking: Unchecked critical commands..."
{ {
echo "## CHECK 27: Critical commands without exit status checks" echo "## CHECK 27: Critical commands without exit status checks"
echo "Severity: MEDIUM" echo "Severity: MEDIUM"
@@ -831,7 +831,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 28: Incorrect string/number comparison (HIGH - type confusion) # CHECK 28: Incorrect string/number comparison (HIGH - type confusion)
#============================================================================== #==============================================================================
echo "[28/30] Checking: Type confusion in comparisons..." echo "[28/31] Checking: Type confusion in comparisons..."
{ {
echo "## CHECK 28: Using wrong comparison operators" echo "## CHECK 28: Using wrong comparison operators"
echo "Severity: HIGH" echo "Severity: HIGH"
@@ -856,7 +856,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 29: Unsafe array iteration (MEDIUM - word splitting) # CHECK 29: Unsafe array iteration (MEDIUM - word splitting)
#============================================================================== #==============================================================================
echo "[29/30] Checking: Unsafe array expansions..." echo "[29/31] Checking: Unsafe array expansions..."
{ {
echo "## CHECK 29: Array iteration without quotes" echo "## CHECK 29: Array iteration without quotes"
echo "Severity: MEDIUM" echo "Severity: MEDIUM"
@@ -882,7 +882,7 @@ echo ""
#============================================================================== #==============================================================================
# CHECK 30: Hardcoded credentials or secrets (CRITICAL - security) # CHECK 30: Hardcoded credentials or secrets (CRITICAL - security)
#============================================================================== #==============================================================================
echo "[30/30] Checking: Hardcoded credentials..." echo "[30/31] Checking: Hardcoded credentials..."
{ {
echo "## CHECK 30: Hardcoded passwords/API keys" echo "## CHECK 30: Hardcoded passwords/API keys"
echo "Severity: CRITICAL" echo "Severity: CRITICAL"
@@ -901,6 +901,59 @@ done < <(grep -rniE '(password|passwd|api_key|apikey|secret|token)=' "$TOOLKIT_P
echo "" echo ""
} >> "$REPORT" } >> "$REPORT"
#==============================================================================
# CHECK 31: local keyword outside functions (CRITICAL - script fails)
#==============================================================================
echo "[31/31] Checking: 'local' outside functions..."
{
echo "## CHECK 31: 'local' keyword outside function context"
echo "Severity: CRITICAL"
echo "Issue: 'local' can only be used inside functions, causes runtime error"
echo ""
while read -r file; do
# Read entire file and track function boundaries
in_function=0
brace_depth=0
line_num=0
while IFS= read -r line_content; do
line_num=$((line_num + 1))
# Skip comments
if echo "$line_content" | grep -q '^\s*#'; then
continue
fi
# Detect function start
if echo "$line_content" | grep -qE '^\s*[a-zA-Z_][a-zA-Z0-9_]*\s*\(\)'; then
in_function=1
brace_depth=0
fi
# Track braces
open_braces=$(echo "$line_content" | grep -o '{' | wc -l)
close_braces=$(echo "$line_content" | grep -o '}' | wc -l)
brace_depth=$((brace_depth + open_braces - close_braces))
# If we were in a function and braces are now balanced back to 0, we've exited
if [ "$in_function" -eq 1 ] && [ "$brace_depth" -le 0 ]; then
in_function=0
fi
# Check for 'local' keyword outside function
if [ "$in_function" -eq 0 ]; then
if echo "$line_content" | grep -qE '^\s*local\s+[a-zA-Z_]'; then
echo "CRITICAL|$file|$line_num|'local' keyword outside function (runtime error)"
count_issue "CRITICAL"
fi
fi
done < "$file"
done < <(find "$TOOLKIT_PATH" -name "*.sh" -type f 2>/dev/null)
echo ""
} >> "$REPORT"
#============================================================================== #==============================================================================
# PERFORMANCE CHECKS (INFO level - not counted as issues) # PERFORMANCE CHECKS (INFO level - not counted as issues)
#============================================================================== #==============================================================================