Protection anti-brute-force sur OmniOS CE

Introduction

OmniOS CE utilise IPFilter (ipf) comme pare-feu, qui ne dispose pas de mécanisme natif de rate-limiting comme PF sur FreeBSD. De plus, fail2ban n'est pas disponible dans les dépôts officiels OmniOS.

Cet article présente un script shell léger qui reproduit les fonctionnalités essentielles de fail2ban : surveiller les logs d'authentification, détecter les tentatives d'intrusion, et bloquer automatiquement les adresses IP malveillantes via IPFilter.


Prérequis

Vérification des prérequis :

# Vérifier rsyslog
svcs system-log:rsyslog
ls -la /var/log/authlog

# Vérifier IPFilter
svcs ipfilter
ipfstat -io

Fonctionnement

Le script fonctionne selon le principe suivant :


Installation

Étape 1 : Créer le répertoire de données

mkdir -p /var/db/bruteforce
touch /var/log/bruteforce.log

Étape 2 : Script principal de blocage

cat << 'EOF' > /opt/local/sbin/block-bruteforce
#!/bin/sh

LOGFILE="/var/log/authlog"
THRESHOLD=5
BLOCK_TIME=3600 # 1 heure en secondes
BLOCKLIST="/var/db/bruteforce/blocked-ips"
WHITELIST="127.0.0.1 192.168.25." # Adapter à votre réseau

# Créer les fichiers si nécessaires
mkdir -p /var/db/bruteforce
touch "$BLOCKLIST"

# Fonction pour vérifier si une IP est en whitelist
is_whitelisted() {
 ip="$1"
 for w in $WHITELIST; do
 case "$ip" in
 ${w}*) return 0 ;;
 esac
 done
 return 1
}

# Nettoyer les blocages expirés
NOW=$(date +%s)
TEMP="/tmp/blocklist.$$"
> "$TEMP"
while IFS=' ' read -r ip timestamp; do
 [ -z "$ip" ] && continue
 EXPIRE=$((timestamp + BLOCK_TIME))
 if [ "$NOW" -lt "$EXPIRE" ]; then
 echo "$ip $timestamp" >> "$TEMP"
 else
 # Débloquer l'IP via ipf
 echo "block in quick from $ip to any" | ipf -rf -
 echo "$(date '+%Y-%m-%d %H:%M:%S'): Débloqué $ip (expiration)" >> /var/log/bruteforce.log
 fi
done < "$BLOCKLIST"
mv "$TEMP" "$BLOCKLIST"

# Analyser les échecs récents
grep -E "Failed password|Invalid user" "$LOGFILE" 2>/dev/null | \
 grep "$(date '+%b %d')" | \
 grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | \
 sort | uniq -c | sort -rn | \
while read count ip; do
 [ -z "$ip" ] && continue
 
 # Vérifier si déjà bloqué
 grep -q "^$ip " "$BLOCKLIST" 2>/dev/null && continue
 
 # Vérifier whitelist
 is_whitelisted "$ip" && continue
 
 # Bloquer si seuil dépassé
 if [ "$count" -ge "$THRESHOLD" ]; then
 echo "$ip $(date +%s)" >> "$BLOCKLIST"
 echo "block in quick from $ip to any" | ipf -f -
 echo "$(date '+%Y-%m-%d %H:%M:%S'): Bloqué $ip ($count tentatives)" >> /var/log/bruteforce.log
 fi
done
EOF
chmod 700 /opt/local/sbin/block-bruteforce

Étape 3 : Script de statut

cat << 'EOF' > /opt/local/sbin/bruteforce-status
#!/bin/sh

BLOCKLIST="/var/db/bruteforce/blocked-ips"
BLOCK_TIME=3600

echo "=== IPs actuellement bloquées ==="
if [ -s "$BLOCKLIST" ]; then
 NOW=$(date +%s)
 while IFS=' ' read -r ip timestamp; do
 [ -z "$ip" ] && continue
 REMAIN=$(( (timestamp + BLOCK_TIME - NOW) / 60 ))
 echo "$ip (expire dans ${REMAIN} min)"
 done < "$BLOCKLIST"
else
 echo "(aucune)"
fi

echo ""
echo "=== Dernières entrées du log ==="
tail -10 /var/log/bruteforce.log 2>/dev/null || echo "(aucun log)"

echo ""
echo "=== Règles IPFilter actives (block) ==="
ipfstat -io 2>/dev/null | grep "block in quick from" || echo "(aucune règle de blocage dynamique)"
EOF
chmod 700 /opt/local/sbin/bruteforce-status

Étape 4 : Script de déblocage manuel

cat << 'EOF' > /opt/local/sbin/bruteforce-unblock
#!/bin/sh

if [ -z "$1" ]; then
 echo "Usage: bruteforce-unblock <IP>"
 exit 1
fi

IP="$1"
BLOCKLIST="/var/db/bruteforce/blocked-ips"

# Retirer de la liste
grep -v "^$IP " "$BLOCKLIST" > "/tmp/blocklist.$$"
mv "/tmp/blocklist.$$" "$BLOCKLIST"

# Retirer la règle IPFilter
echo "block in quick from $IP to any" | ipf -rf -

echo "$(date '+%Y-%m-%d %H:%M:%S'): Débloqué manuellement $IP" >> /var/log/bruteforce.log
echo "IP $IP débloquée"
EOF
chmod 700 /opt/local/sbin/bruteforce-unblock

Étape 5 : Planification cron

# Ajouter au crontab (exécution toutes les minutes)
crontab -l > /tmp/crontab.tmp
echo "" >> /tmp/crontab.tmp
echo "# Anti-brute-force (toutes les min)" >> /tmp/crontab.tmp
echo "1 * * * * /opt/local/sbin/block-bruteforce" >> /tmp/crontab.tmp
crontab /tmp/crontab.tmp
rm /tmp/crontab.tmp

# Vérifier
crontab -l | grep bruteforce

Configuration

Les paramètres sont définis en haut du script /opt/local/sbin/block-bruteforce :

(Adapter la whitelist à votre réseau local pour éviter de vous bloquer vous-même)


Utilisation

Voir le statut

bruteforce-status

# Exemple de sortie :
=== IPs actuellement bloquées ===
203.0.113.45 (expire dans 42 min)
198.51.100.23 (expire dans 17 min)

=== Dernières entrées du log ===
2025-12-30 16:22:00: Bloqué 203.0.113.45 (15 tentatives)
2025-12-30 16:35:00: Bloqué 198.51.100.23 (8 tentatives)

=== Règles IPFilter actives (block) ===
block in quick from 203.0.113.45/32 to any
block in quick from 198.51.100.23/32 to any

Débloquer une IP manuellement

bruteforce-unblock 203.0.113.45

# Sortie :
IP 203.0.113.45 débloquée

Exécution manuelle

# Forcer une analyse immédiate
/opt/local/sbin/block-bruteforce

Consulter les logs

# Log du script anti-brute-force
cat /var/log/bruteforce.log

# Log des authentifications (source)
tail -50 /var/log/authlog | grep -E "Failed|Invalid"

Fichiers et emplacements


Comparaison avec fail2ban

Aspect Ce script fail2ban
Dépendances Aucune (shell POSIX) Python
Installation Copier les scripts pkgin
Configuration Simple (variables) Fichiers jail.conf
Services supportés SSH uniquement Multiples
Réactivité Cron (1 min) Temps réel
Ressources Très légères Modérées
Disponibilité OmniOS Natif Via pkgsrc

Dépannage

Le script ne bloque pas les IPs

Je me suis bloqué moi-même

Les blocages ne persistent pas après reboot

C'est le comportement attendu. Les règles IPFilter dynamiques sont perdues au redémarrage. La liste /var/db/bruteforce/blocked-ips est conservée mais les règles doivent être réappliquées. Pour une persistance complète, ajouter dans /etc/ipf/ipf.conf les IPs à bloquer définitivement.


Améliorations possibles


Notifications

Il est aisé d'ajouter des notifications lors du blocage d'une IP en utilisant un service comme ntfy.sh. Il suffit d'ajouter un appel curl dans le script principal, juste après la ligne de log du blocage :

curl -s -d "IP $ip bloquée ($count tentatives)" https://ntfy.sh/VOTRE_TOPIC

Conclusion

Ce script offre une protection efficace contre les attaques par brute-force SSH sur OmniOS CE, sans nécessiter de dépendances externes. Sa légèreté et sa simplicité en font une solution idéale pour les serveurs NAS et les environnements où les ressources sont limitées.



↑ Haut de page