Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - UlrichC

#1
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
#!/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"

################################################################################