Hallo Allerseits,
ich betreibe die OPNsense nun als Ersatz für eine Sophos XG Firewall und muss sagen: "Das hat sich gelohnt!"
Ich betreibe ein kleines Rechenzentrum und gebe daher verschiedene Dienste offen raus (25,443,465,587,993,995). Da hier gerne rumgehackt wird, habe ich ein kleines Skript geschrieben, was a) die Zugriffe einzelner IP-Adresse zählt und diese dann Netzen zuordnet. So kann ich sehen, aus welchem Netz distributierte Angriffe kommen. Das Skript legt eine Datei ab, die als Alias eingebunden werden kann. Aktuell nutze ich sie nicht als automatisierten block, doch kann ich so gut sehen woher das ganze kommt. Vielleicht könnte man es noch nutzen, um auf mehreren OPNsense diese Informationen zu sammeln?
Ich freue mich, wenn ihr es mal ausprobiert.
Wichtig: Relativ weit oben sind ein paar Parameter zu setzen. Mein WAN-Port ist "pppoe0", hier müsst ihr natürlich euren einsetzen.
Das Skript hat drei Parameter:
1) Sammelzeit in Sekunden
Je nachdem was los ist kann man hier mal mit 10 oder 60 Sekunden starten.
2) Port
. : alle Ports
25 : nur Port 25
a : für Ports 25,443,465,587,993,995
3) Anzahl der IP-Adressen pro Netz
Ab welcher Anzahl der gefundenen IP-Adressen pro Netz soll das Netz in der Alias-Datei vermerkt werden.
Standard: 1 - Das ist natürlich nur, um zu sehen, ob es überhaupt funktioniert.
Interne Variablen:
KEEP_SEC
Sekunden bis ein Eintrag wieder aus der Alias-Datei entfernt wird.
WAN_PORT
Interfacename des WAN-Ports auf dem der Traffic beobachtet werden soll. Bei mir: pppoe0
Beispiel:
./synlog.sh 10 a
So kann man sehen ob es funktioniert.
./synlog.sh 300 a 5
Laufzeit: 5 Minuten
Nur wichtige Ports.
Mindestens 5 IP-Adressen pro Bereich.
Fragen? Fragen.
Grüße
Ulrich
synlog.sh
ich betreibe die OPNsense nun als Ersatz für eine Sophos XG Firewall und muss sagen: "Das hat sich gelohnt!"
Ich betreibe ein kleines Rechenzentrum und gebe daher verschiedene Dienste offen raus (25,443,465,587,993,995). Da hier gerne rumgehackt wird, habe ich ein kleines Skript geschrieben, was a) die Zugriffe einzelner IP-Adresse zählt und diese dann Netzen zuordnet. So kann ich sehen, aus welchem Netz distributierte Angriffe kommen. Das Skript legt eine Datei ab, die als Alias eingebunden werden kann. Aktuell nutze ich sie nicht als automatisierten block, doch kann ich so gut sehen woher das ganze kommt. Vielleicht könnte man es noch nutzen, um auf mehreren OPNsense diese Informationen zu sammeln?
Ich freue mich, wenn ihr es mal ausprobiert.
Wichtig: Relativ weit oben sind ein paar Parameter zu setzen. Mein WAN-Port ist "pppoe0", hier müsst ihr natürlich euren einsetzen.
Das Skript hat drei Parameter:
1) Sammelzeit in Sekunden
Je nachdem was los ist kann man hier mal mit 10 oder 60 Sekunden starten.
2) Port
. : alle Ports
25 : nur Port 25
a : für Ports 25,443,465,587,993,995
3) Anzahl der IP-Adressen pro Netz
Ab welcher Anzahl der gefundenen IP-Adressen pro Netz soll das Netz in der Alias-Datei vermerkt werden.
Standard: 1 - Das ist natürlich nur, um zu sehen, ob es überhaupt funktioniert.
Interne Variablen:
KEEP_SEC
Sekunden bis ein Eintrag wieder aus der Alias-Datei entfernt wird.
WAN_PORT
Interfacename des WAN-Ports auf dem der Traffic beobachtet werden soll. Bei mir: pppoe0
Beispiel:
./synlog.sh 10 a
So kann man sehen ob es funktioniert.
./synlog.sh 300 a 5
Laufzeit: 5 Minuten
Nur wichtige Ports.
Mindestens 5 IP-Adressen pro Bereich.
Fragen? Fragen.
Grüße
Ulrich
synlog.sh
Code Select
#!/bin/sh
################################################################################
### (C) by Ulrich C. Thiess, ZOOMsoft GmbH
################################################################################
################################################################################
### log file if run with cron
################################################################################
if [ ! -t 1 ]; then
exec >> "/var/log/synlog.log" 2>&1
fi
################################################################################
### ctrl-c also stops counter
################################################################################
cleanup() {
[ -n "$COUNTER_PID" ] && kill "$COUNTER_PID" 2>/dev/null
wait "$COUNTER_PID" 2>/dev/null
printf "\r \r"
exit 130
}
trap cleanup INT TERM
################################################################################
### vars and sudo suff
################################################################################
echo
ALIAS_FILE="/var/db/synlog.txt"
KEEP_SEC=7200
LOG_FILE="/var/log/synlog_$(date +%Y%m%d-%H%M%S).log"
ME="$(id -un)"
NOW="$(date '+%Y-%m-%d %H:%M:%S')"
NOW_EPOCH="$(date '+%s')"
TMP_ALL="$(mktemp)" || exit 1
TMP_NEW="$(mktemp)" || exit 1
TMP_OLD="$(mktemp)" || exit 1
WAN_PORT="pppoe0"
WEB_DIR="/usr/local/www/aliases"
WEB_FILE="$WEB_DIR/synlog.txt"
if ! sudo -n true 2>/dev/null; then
sudo -v || exit 1
printf "\033[1A\033[2K\r"
fi
sudo mkdir -p "$WEB_DIR"
sudo touch "$ALIAS_FILE"
sudo touch "$LOG_FILE"
sudo chown "$ME" "$LOG_FILE"
sudo chmod 644 "$LOG_FILE"
sudo chown "$ME" "$ALIAS_FILE"
sudo chmod 644 "$ALIAS_FILE"
sudo ln -sf "$ALIAS_FILE" "$WEB_FILE"
################################################################################
### only 24 log files (each 5min for 2 hours = 24 files)
################################################################################
sudo find /var/log -maxdepth 1 -type f -name 'synlog_*.log' \
| sort -r \
| awk 'NR > 24' \
| xargs -r sudo rm -f
################################################################################
### parameter 1 : duration
################################################################################
if [ $# -ge 1 ] && [ "$1" -eq "$1" ] 2>/dev/null; then
DURATION="$1"
else
DURATION=10
fi
################################################################################
### parameter 2 : ports
################################################################################
FILTER="tcp[tcpflags] & tcp-syn != 0 and host 185.37.248.21"
if [ $# -ge 2 ] && [ "$2" != "." ]; then
if [ "$2" = "a" ]; then
PORT="25,80,443,465,587,993,995"
else
PORT="$2"
fi
PORTFILTER=$(printf "%s\n" "$PORT" \
| tr ',' '\n' \
| awk '{printf "port %s or ", $1}' \
| sed 's/ or $//')
FILTER="($FILTER) and ($PORTFILTER)"
else
PORT=""
fi
################################################################################
### parameter 3 : how many ip from net to block
################################################################################
if [ $# -ge 3 ] && [ "$3" -eq "$3" ] 2>/dev/null; then
NETIPS="$3"
else
NETIPS=1
fi
################################################################################
### counter
################################################################################
( for i in $(jot "$DURATION" "$DURATION" 1); do printf "\r%2d " "$i"; sleep 1; done; printf "\r \r... "; ) &
COUNTER_PID=$!
################################################################################
### new connecions
################################################################################
IPS=$(
sudo timeout "$DURATION" \
tcpdump -n -l -tt -i $WAN_PORT "$FILTER" 2>/dev/null \
| awk -v target="185.37.248.21" '
$3 ~ /^[0-9]+\./ && $5 ~ /^[0-9]+\./ {
split($3,a,".")
srcip = a[1]"."a[2]"."a[3]"."a[4]
srcport = a[5]
sub(":", "", srcport)
split($5,b,".")
dstip = b[1]"."b[2]"."b[3]"."b[4]
dstport = b[5]
sub(":", "", dstport)
flags = $7
gsub(/[\[\],]/, "", flags)
if (flags == "S" && dstip == target) {
key = srcip ":" srcport ">" dstip ":" dstport
syn[key] = 1
}
else if (flags == "S." && srcip == target) {
rev = dstip ":" dstport ">" srcip ":" srcport
if (syn[rev]) {
ok[dstip ":" srcport]++
}
}
}
END {
for (k in ok) {
split(k,x,":")
printf "%8d %-15s %5s\n", ok[k], x[1], x[2]
}
}
' \
| sort -k1,1nr -k2,2V \
| while read cnt ip port; do
hostnames=$(host -W 0 "$ip" 2>/dev/null \
| awk '/domain name pointer/ {print $5}' \
| sed 's/\.$//' \
| sort -u \
| paste -sd, - \
| sed 's/,/, /g')
printf "%8s %-15s %5s %s\n" "$cnt" "$ip" "$port" "${hostnames:-"-"}"
done
)
if [ -n "$IPS" ]; then
IPS=$(
printf "%8s %-15s %5s %s\n" "Count" "IP" "Port" "RDNS"; \
printf "%8s %-15s %5s %s\n" "--------" "---------------" "-----" "----"; \
printf "%s" "$IPS"
)
fi
################################################################################
### stop counter
################################################################################
kill "$COUNTER_PID" 2>/dev/null
wait "$COUNTER_PID" 2>/dev/null
################################################################################
### display and log IPs
################################################################################
printf "\r \r"
if [ -n "$IPS" ]; then
printf "\n%ss\n\n%s\n\n" "$DURATION" "$IPS" >> "$LOG_FILE"
printf "%ss\n\n%s\n\n" "$DURATION" "$IPS"
fi
################################################################################
### nets from ips
################################################################################
NETS=$(
printf "%s\n" "$IPS" \
| awk 'NR > 2 {print $2}' \
| sort -u \
| while read ip; do
timeout 3 whois -h whois.cymru.com " -v $ip" 2>/dev/null \
| awk -F'|' '
NR > 1 {
for (i=1; i<=NF; i++) gsub(/^[ \t]+|[ \t]+$/, "", $i)
if ($3 != "" && $3 != "BGP Prefix") {
asname = $7
for (i=8; i<=NF; i++) asname = asname " | " $i
printf "%s\t%s\t%s\n", $3, $4, asname
}
}
'
done \
| sort \
| uniq -c \
| awk -v min="$NETIPS" '
BEGIN { OFS="\t" }
{
count = $1
sub(/^[[:space:]]*[0-9]+[[:space:]]+/, "", $0)
split($0, a, "\t")
if (count >= min) {
printf "%8d\t%s\t%s\t%s\n", count, a[1], a[2], a[3]
}
}
' \
| sort -k1,1nr -k2,2V \
| awk -F'\t' '{printf "%8d %-18s %2s %s\n", $1, $2, $3, $4}'
)
if [ -n "$NETS" ]; then
NETS=$(
printf "%8s %-18s %2s %s\n" "IPs" "BGP-Prefix" "CC" "AS Name"; \
printf "%8s %-18s %2s %s\n" "--------" "------------------" "--" "-------"; \
printf "%s" "$NETS"
)
fi
if [ -n "$NETS" ]; then
printf "%s\n\n" "$NETS" >> "$LOG_FILE"
printf "%s\n\n" "$NETS"
fi
################################################################################
###############################################################################
# Alte Einträge behalten, wenn sie noch nicht abgelaufen sind
###############################################################################
if test -f "$ALIAS_FILE"; then
cat "$ALIAS_FILE" | while IFS= read -r line; do
ts=$(printf "%s\n" "$line" | sed -n 's/.*# \([0-9-][0-9-]* [0-9:][0-9:]*\).*/\1/p')
[ -z "$ts" ] && continue
ts_epoch=$(date -j -f "%Y-%m-%d %H:%M:%S" "$ts" "+%s" 2>/dev/null)
[ -z "$ts_epoch" ] && continue
age=$((NOW_EPOCH - ts_epoch))
if [ "$age" -le "$KEEP_SEC" ]; then
printf "%s\n" "$line"
fi
done > "$TMP_OLD"
else
: > "$TMP_OLD"
fi
###############################################################################
# Neue Einträge aus NETS erzeugen
###############################################################################
if [ -n "$NETS" ]; then
printf "%s\n" "$NETS" \
| awk -v now="$NOW" -v dur="$DURATION" '
NR > 2 && $1 ~ /^[0-9]+$/ && $2 ~ /^[0-9.]+\/[0-9]+$/ {
asname = $4
for (i = 5; i <= NF; i++) asname = asname " " $i
printf "%-18s # %s | %8ss | %4s | %s\n", $2, now, dur, $1, asname
}
' > "$TMP_NEW"
else
: > "$TMP_NEW"
fi
###############################################################################
# Alte + neue zusammenführen, nach Netz deduplizieren
###############################################################################
cat "$TMP_OLD" "$TMP_NEW" \
| awk '!seen[$1]++' \
| sort -V \
> "$TMP_ALL"
###############################################################################
# Datei immer schreiben, auch wenn sie leer ist
###############################################################################
cat "$TMP_ALL" > "$ALIAS_FILE"
rm -f "$TMP_OLD" "$TMP_NEW" "$TMP_ALL"
################################################################################
"