From dd643b7d0e66a2c2335fe09438298674506ad4c0 Mon Sep 17 00:00:00 2001 From: cschantz Date: Sat, 13 Dec 2025 02:40:15 -0500 Subject: [PATCH] Rewrite historical attack analyzer to show per-IP summaries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- tools/analyze-historical-attacks.sh | 138 ++++++++++++++++++++++------ 1 file changed, 110 insertions(+), 28 deletions(-) diff --git a/tools/analyze-historical-attacks.sh b/tools/analyze-historical-attacks.sh index e113935..2071709 100755 --- a/tools/analyze-historical-attacks.sh +++ b/tools/analyze-historical-attacks.sh @@ -26,6 +26,9 @@ source "$SCRIPT_DIR/lib/http-attack-analyzer.sh" 2>/dev/null || { exit 1 } +# Try to source IP reputation library (optional) +source "$SCRIPT_DIR/lib/ip-reputation.sh" 2>/dev/null + # Colors RED='\033[0;31m' YELLOW='\033[1;33m' @@ -148,6 +151,9 @@ MEDIUM_ATTACKS=0 declare -A ATTACK_TYPES declare -A TOP_ATTACKERS 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 show_progress() { @@ -231,22 +237,36 @@ uri="${temp#*||}" ATTACK_TYPES["$type"]=$((${ATTACK_TYPES[$type]:-0} + 1)) done - # Track top attackers + # Track top attackers (cumulative 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]}" + url_count=$(echo "$current_urls" | grep -o "||" | wc -l) + if [ "$url_count" -lt 3 ]; then + if [ -z "$current_urls" ]; then + IP_SAMPLE_URLS["$ip"]="${uri:0:100}" + else + IP_SAMPLE_URLS["$ip"]="$current_urls||${uri:0:100}" + fi + fi + # Track signatures IFS=',' read -ra sigs <<< "$signatures" for sig in "${sigs[@]}"; do SIGNATURE_HITS["$sig"]=$((${SIGNATURE_HITS[$sig]:-0} + 1)) 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 done < <($CAT_CMD "$log_file" 2>/dev/null) @@ -254,6 +274,83 @@ uri="${temp#*||}" done echo "" >> "$OUTPUT_FILE" + echo "================================================================================ +" >> "$OUTPUT_FILE" + echo "ATTACKING IPs - DETAILED BREAKDOWN" >> "$OUTPUT_FILE" + echo "================================================================================ +" >> "$OUTPUT_FILE" + echo "" >> "$OUTPUT_FILE" + + # Sort IPs by cumulative threat score and display + # Create sorted list first to avoid subshell issues + sorted_ips=$(for ip in "${!TOP_ATTACKERS[@]}"; do + echo "${TOP_ATTACKERS[$ip]}:$ip" + 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" >> "$OUTPUT_FILE" + printf " Attacks: %d | Avg Score: %d | Threat Level: %s\n" "$attack_count" "$avg_score" "$level" >> "$OUTPUT_FILE" + echo " Attack Types: $attack_summary" >> "$OUTPUT_FILE" + + # 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}" >> "$OUTPUT_FILE" + fi + fi + fi + + # Show sample URLs + if [ -n "$sample_urls" ]; then + echo " Sample Targets:" >> "$OUTPUT_FILE" + IFS='||' read -ra urls <<< "$sample_urls" + for url in "${urls[@]}"; do + echo " - $url" >> "$OUTPUT_FILE" + done + fi + + echo "" >> "$OUTPUT_FILE" + done <<< "$sorted_ips" + echo "================================================================================ " >> "$OUTPUT_FILE" echo "SUMMARY STATISTICS" >> "$OUTPUT_FILE" @@ -262,6 +359,9 @@ uri="${temp#*||}" echo "" >> "$OUTPUT_FILE" echo "Total lines processed: $TOTAL_LINES" >> "$OUTPUT_FILE" echo "Total attacks detected: $TOTAL_ATTACKS" >> "$OUTPUT_FILE" + echo "Unique attacking IPs: ${#TOP_ATTACKERS[@]}" >> "$OUTPUT_FILE" + echo "" >> "$OUTPUT_FILE" + echo "Attack Severity:" >> "$OUTPUT_FILE" echo " - Critical (≥85): $CRITICAL_ATTACKS" >> "$OUTPUT_FILE" echo " - High (70-84): $HIGH_ATTACKS" >> "$OUTPUT_FILE" echo " - Medium (50-69): $MEDIUM_ATTACKS" >> "$OUTPUT_FILE" @@ -271,29 +371,11 @@ uri="${temp#*||}" echo "Top Attack Types:" >> "$OUTPUT_FILE" for type in "${!ATTACK_TYPES[@]}"; do 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" done echo "" >> "$OUTPUT_FILE" - # 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 "================================================================================ " >> "$OUTPUT_FILE" echo "END OF REPORT" >> "$OUTPUT_FILE"