-
Notifications
You must be signed in to change notification settings - Fork 1
/
reporter.sh
217 lines (181 loc) · 6.72 KB
/
reporter.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
#!/bin/bash
###
# https://github.com/sefinek24/UFW-AbuseIPDB-Reporter
# Version v1.0.1 from 14.09.2024 [DD.MM.YYYY]
##
LOG_FILE="/var/log/ufw.log"
ENCODED_API_KEY_FILE="./.abuseipdb_token"
REPORTED_IPS_FILE="/tmp/ufw-abuseipdb-reporter.cache"
REPORT_INTERVAL=43200 # 12h (seconds)
declare -A reported_ips
log() {
local level="$1"
local message="$2"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $message"
}
# Check if the API key file exists and decode it
if [[ -f "$ENCODED_API_KEY_FILE" ]]; then
DECODED_API_KEY=$(openssl enc -d -base64 -in "$ENCODED_API_KEY_FILE")
if [[ -z "$DECODED_API_KEY" ]]; then
log "ERROR" "Failed to decode API key from $ENCODED_API_KEY_FILE"
exit 1
fi
else
log "ERROR" "API key file not found at $ENCODED_API_KEY_FILE"
exit 1
fi
ABUSEIPDB_API_KEY="$DECODED_API_KEY"
# Check if jq, curl, or wget packages are available
if ! command -v jq &> /dev/null; then
log "ERROR" "jq is not installed. Please install jq to run this script."
exit 1
fi
if ! command -v curl &> /dev/null && ! command -v wget &> /dev/null; then
log "ERROR" "Neither curl nor wget is available. Please install one of them to continue."
exit 1
fi
load_reported_ips() {
if [[ -f "$REPORTED_IPS_FILE" ]]; then
while IFS= read -r line; do
[[ -z "$line" ]] && continue
IFS=' ' read -r ip report_time <<< "$line"
if [[ -n "$ip" && -n "$report_time" ]]; then
reported_ips["$ip"]=$report_time
else
log "WARN" "Invalid line format: '$line'"
fi
done < "$REPORTED_IPS_FILE"
log "INFO" "Loaded ${#reported_ips[@]} IPs from $REPORTED_IPS_FILE"
else
log "INFO" "$REPORTED_IPS_FILE does not exist. No data to load!"
fi
}
save_reported_ips() {
: > "$REPORTED_IPS_FILE"
for ip in "${!reported_ips[@]}"; do
echo "$ip ${reported_ips[$ip]}" >> "$REPORTED_IPS_FILE"
done
}
is_local_ip() {
local ip="$1"
[[ "$ip" =~ ^(10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.|127\.|fc|fd|fe80|::1) ]]
}
report_to_abuseipdb() {
local ip="$1" categories="$2" proto="$3" spt="$4" dpt="$5" ttl="$6" len="$7" tos="$8" warsaw_time="$9"
local comment="Blocked by UFW ($proto on port $dpt).
Source port: $spt"
[[ -n "$ttl" ]] && comment+="
TTL: $ttl"
[[ -n "$len" ]] && comment+="
Packet length: $len"
[[ -n "$tos" ]] && comment+="
TOS: $tos"
comment+="
Timestamp: $warsaw_time [Europe/Warsaw]
This report (for $ip) was generated by:
https://github.com/sefinek24/UFW-AbuseIPDB-Reporter"
local res
if command -v curl >/dev/null 2>&1; then
res=$(curl -s -X POST "https://api.abuseipdb.com/api/v2/report" \
--data-urlencode "ip=$ip" \
--data-urlencode "categories=$categories" \
--data-urlencode "comment=$comment" \
-H "Key: $ABUSEIPDB_API_KEY" \
-H "Accept: application/json")
elif command -v wget >/dev/null 2>&1; then
res=$(wget -qO- --post-data="ip=$ip&categories=$categories&comment=$comment" \
--header="Key: $ABUSEIPDB_API_KEY" \
--header="Accept: application/json" \
"https://api.abuseipdb.com/api/v2/report")
else
log "ERROR" "Neither curl nor wget is available to send the report."
return 1
fi
local abuse_confidence_score
abuse_confidence_score=$(echo "$res" | jq -r '.data.abuseConfidenceScore')
if [[ "$abuse_confidence_score" =~ ^[0-9]+$ ]]; then
log "INFO" "Successfully reported IP $ip to AbuseIPDB with score: $abuse_confidence_score"
return 0
else
log "ERROR" "Failed to report IP $ip to AbuseIPDB: $res"
return 1
fi
}
is_ip_reported_recently() {
local ip="$1"
local current_time
current_time=$(date +%s)
if [[ -v reported_ips["$ip"] ]]; then
local report_time=${reported_ips["$ip"]}
(( current_time - report_time < REPORT_INTERVAL )) && return 0
fi
return 1
}
mark_ip_as_reported() {
local ip="$1"
reported_ips["$ip"]=$(date +%s)
}
determine_categories() {
local proto="$1"
local dpt="$2"
# See https://www.abuseipdb.com/categories for more
case "$proto" in
"TCP")
case "$dpt" in
22) echo "14,22,18" ;; # Port Scan | SSH | Brute-Force
80 | 443 | 8080) echo "14,21" ;; # Port Scan | Web App Attack
25) echo "11" ;; # Email Spam
21) echo "5,18" ;; # FTP Brute-Force | Brute-Force
53) echo "1,2" ;; # DNS Compromise | DNS Poisoning
23 | 3389) echo "14,15,18" ;; # Port Scan | Hacking | Brute-Force
3306) echo "16" ;; # SQL Injection
6666 | 6667 | 6668 | 6669) echo "14,8" ;; # Port Scan | Fraud VoIP
9999) echo "6" ;; # Ping of Death
*) echo "14" ;; # Port Scan
esac
;;
"UDP")
case "$dpt" in
53) echo "14,1,2" ;; # Port Scan | DNS Compromise | DNS Poisoning
123) echo "14,17" ;; # Port Scan | Spoofing
*) echo "14" ;; # Port Scan
esac
;;
*) echo "14,15" ;; # Port Scan | Hacking
esac
}
process_log_line() {
local line="$1"
if [[ "$line" == *"[UFW BLOCK]"* ]]; then
local timestamp src_ip proto spt dpt ttl len tos categories warsaw_time
timestamp=$(echo "$line" | awk '{print $1, $2, $3}')
[[ -z "$timestamp" ]] && timestamp=$(date '+%Y-%m-%d %H:%M:%S')
src_ip=$(echo "$line" | grep -oP 'SRC=\K[^\s]+')
if is_local_ip "$src_ip"; then
log "INFO" "Ignoring local IP: $src_ip"
return
fi
proto=$(echo "$line" | grep -oP 'PROTO=\K[^\s]+')
spt=$(echo "$line" | grep -oP 'SPT=\K[^\s]+')
dpt=$(echo "$line" | grep -oP 'DPT=\K[^\s]+')
ttl=$(echo "$line" | grep -oP 'TTL=\K[^\s]+')
len=$(echo "$line" | grep -oP 'LEN=\K[^\s]+')
tos=$(echo "$line" | grep -oP 'TOS=\K[^\s]+')
if is_ip_reported_recently "$src_ip"; then
log "INFO" "IP $src_ip ($proto) was reported recently. Skipping..."
return
fi
categories=$(determine_categories "$proto" "$dpt")
warsaw_time=$(TZ="Europe/Warsaw" date -d "$timestamp" '+%Y-%m-%d %H:%M:%S')
log "INFO" "Reporting IP $src_ip ($proto $dpt) with categories $categories..."
if report_to_abuseipdb "$src_ip" "$categories" "$proto" "$spt" "$dpt" "$ttl" "$len" "$tos" "$warsaw_time"; then
mark_ip_as_reported "$src_ip"
save_reported_ips
fi
fi
}
load_reported_ips
log "INFO" "Starting to monitor $LOG_FILE"
tail -Fn0 "$LOG_FILE" | while read -r line; do
process_log_line "$line"
done