Skip to content

Instantly share code, notes, and snippets.

@LM1LC3N7
Last active January 17, 2023 00:07
Show Gist options
  • Save LM1LC3N7/8b4052bee4e80250de7d8ebeb47127fb to your computer and use it in GitHub Desktop.
Save LM1LC3N7/8b4052bee4e80250de7d8ebeb47127fb to your computer and use it in GitHub Desktop.
Script de paramétrage de IPTables
#!/bin/bash
## SOURCE
## - https://github.com/trimstray/iptables-essentials
## - https://gist.github.com/azlux/6a70bd38bb7c525ab26efe7e3a7ea8ac
#
# =============
# Configuration
# =============
#
iptables="iptables"
ip6tables="ip6tables"
SERVER_IP="X.X.X.X"
broadcastIP="X.X.X.255"
## Niveau appliqués aux logs. loglevel: debug(1), info(3), notice(5), error(7) or fatal(8) (default 5)
logLevelDrop=6
logLevelAccept=3
## Limite de log par minute pour les paquets entrants acceptés
logInputAcceptLimit=120
logInputAcceptBurst=10
## Commande de log pour les paquets DROP
logDropLimit="-m limit --limit 120/min --limit-burst 10"
## Limiter les connexions parallèles (80 & 443 par exemple) maximum par seconde
limitConnTcpPorts="80 443"
limitConnUcpPorts=""
limitConn=5
## Exceptions :
## - Localhost & IP : X.X.X.X
ipExceptions="X.X.X.X 127.0.0.1"
## Bloquer les IP suivantes pour tous les ports sauf 443 :
ipBlocked=""
## Ouvrir les ports en entrée + retour (sauf Docker qui se charge automatiquement de les ouvrir) - TCP
listenTcpPorts="22 8080"
## Idem - UDP
listenUdpPorts=""
## Ouvrir les ports en sortie + retour - TCP
outTcpPorts="22 80 443 53 21 465 587"
## Ouvrir les ports en sortie + retour - UDP
outUdpPorts="53 123"
## Désactiver l'IPv6 (true / false - DEFAUT)
ipv6=false
## Autoriser les connexions localhost (true - DEFAUT / false)
allowLocalhost=true
## Autoriser les connexions docker0 (true - DEFAUT / false)
allowDocker0=true
## Activer les règles de protections (Packets invalides, Scans, etc.) : (true - DEFAULT / false)
enableProtectRules=true
## SSSHguard est-il ou sera-t-il utilisé ? (true - DEFAULT / false)
sshguard=true
SSHGUARD_PORTS="21,22,23,110,143,445,1433,3389"
SSHGUARD_BLOCK_ALL="false"
#
# =====================================
# Reset de toutes les règles existantes
# =====================================
#
# On supprime toutes les règles dans toutes les CHAIN sauf celles de Docker
echo "Réinitialisation des règles iptables."
# Forward est utilisé par Docker, suppression seulement des règles ajoutées par le script.
$iptables -D FORWARD -m pkttype --pkt-type broadcast -d ${broadcastIP} -j DROP > /dev/null 2>&1
$iptables -D FORWARD -d 255.255.255.255 -j DROP > /dev/null 2>&1
$iptables -D FORWARD -j ALLOWED_IPs > /dev/null 2>&1
$iptables -D FORWARD -m conntrack --ctstate INVALID -j DROP > /dev/null 2>&1
$iptables -D FORWARD -p tcp --syn --dport 80 -m connlimit --connlimit-above ${limitConn} -j HTTP-FLOOD > /dev/null 2>&1
$iptables -D FORWARD -p tcp --syn --dport 443 -m connlimit --connlimit-above ${limitConn} -j HTTP-FLOOD > /dev/null 2>&1
$iptables -D FORWARD ${logDropLimit} -j LOG --log-prefix="[DROP][FORWARD] " --log-level $logLevelDrop > /dev/null 2>&1
$iptables -D FORWARD -j DROP > /dev/null 2>&1
$iptables -t mangle -D PREROUTING -p tcp -m conntrack --ctstate NEW -m tcpmss ! --mss 536:65535 -j DROP > /dev/null 2>&1
$iptables -F INPUT
$iptables -F OUTPUT
$iptables -F ALLOWED_IPs > /dev/null 2>&1
$iptables -X ALLOWED_IPs > /dev/null 2>&1
$iptables -F HTTP-FLOOD > /dev/null 2>&1
$iptables -X HTTP-FLOOD > /dev/null 2>&1
$iptables -F port-scanning > /dev/null 2>&1
$iptables -X port-scanning > /dev/null 2>&1
# Don't remove sshguard banned IP list
#$iptables -F sshguard > /dev/null 2>&1
#$iptables -X sshguard > /dev/null 2>&1
$iptables -P INPUT ACCEPT
$iptables -P FORWARD ACCEPT
$iptables -P OUTPUT ACCEPT
# HARD RESET - Avec les règles par Docker
# $iptables -P INPUT ACCEPT
# $iptables -P FORWARD ACCEPT
# $iptables -P OUTPUT ACCEPT
# $iptables -F
# $iptables -X
# $iptables -t nat -F
# $iptables -t mangle -F
# Supprimer les règles ajoutées par Docker ?
confirmation=false
while true; do
read -p "Faut-il supprimer les règles créées par Docker [O/N] ? (n) " yn
yn=${name:-n}
case "$yn" in
y|y|O|o ) confirmation=true ; break ;;
n|N ) break;;
* ) echo "Réponse non reconnue (O/N).";;
esac
done
# Confirmation
if [ ${confirmation} = true ] ; then
while true; do
read -p "Le service docker et ses conteneurs devront être redémarrés, êtes-vous certain [O/N] ? (n) " yn
yn=${name:-n}
case "$yn" in
y|y|O|o ) $iptables -F && $iptables -X && $iptables -t nat -F && $iptables -t mangle -F; break ;;
n|N ) break;;
* ) echo "Réponse non reconnue (O/N).";;
esac
done
fi
echo ""
#
# ====================
# DROP tout par défaut
# ====================
#
echo "DROP par défaut."
# DROP par defaut
$iptables -P INPUT DROP
$iptables -P OUTPUT DROP
$iptables -P FORWARD DROP
# Vérifier les paquets fragmentés
$iptables -A INPUT -f -j LOG --log-prefix "[DROP][INPUT][FRAGMENT] "
$iptables -A INPUT -f -j DROP
## Drop les broadcast (sans logger)
$iptables -A INPUT -m pkttype --pkt-type broadcast -d ${broadcastIP} -j DROP
$iptables -A FORWARD -m pkttype --pkt-type broadcast -d ${broadcastIP} -j DROP
$iptables -A INPUT -d 255.255.255.255 -j DROP
$iptables -A FORWARD -d 255.255.255.255 -j DROP
# Ne pas fermer les connexions déjà établies
# NE PAS UTILISER RELATED : https://gist.github.com/azlux/6a70bd38bb7c525ab26efe7e3a7ea8ac
echo "Sessions actives et flux retours autorisés."
$iptables -A INPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT
$iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT
#
# =========================
# Autorisation du localhost
# =========================
#
if [ ${allowLocalhost} = true ] ; then
echo "Trafic sur localhost autorisé."
$iptables -A INPUT -i lo -j LOG --log-prefix "[ACCEPT][INPUT][LOCALHOST] "
$iptables -A INPUT -i lo -j ACCEPT
$iptables -A OUTPUT -o lo -j LOG --log-prefix "[ACCEPT][OUTPUT][LOCALHOST] "
$iptables -A OUTPUT -o lo -j ACCEPT
else
echo "Trafic sur localhost non autorisé par défaut."
fi
#
# =========================
# Autorisation du trafic sur docker0
# =========================
#
if [ ${allowDocker0} = true ] ; then
echo "Trafic sur docker0 autorisé."
$iptables -A INPUT -i docker0 -j LOG --log-prefix "[ACCEPT][INPUT][DOCKER0] "
$iptables -A INPUT -i docker0 -j ACCEPT
$iptables -A OUTPUT -o docker0 -j LOG --log-prefix "[ACCEPT][OUTPUT][DOCKER0] "
$iptables -A OUTPUT -o docker0 -j ACCEPT
else
echo "Trafic sur docker0 non autorisé par défaut."
fi
#
# =======================
# Désactivation de l'IPv6
# =======================
#
if [ ${ipv6} = true ] ; then
echo "IPv6 ne sera pas bloqué."
else
echo "IPv6 DROP : INPUT / OUTPUT (reject) / FORWARD."
$ip6tables -Z; # zero counters
$ip6tables -F; # flush (delete) rules
$ip6tables -X; # delete all extra chains
$ip6tables -P INPUT DROP
$ip6tables -A OUTPUT -j REJECT
$ip6tables -P OUTPUT DROP
$ip6tables -P FORWARD DROP
fi
#
# =============
# IP Exceptions
# =============
# (Source : http://serverfault.com/a/30046)
#
echo ""
## Créer une nouvelle chain
if [ ! -z "${ipExceptions}" ] ; then
echo "Ajout des IP suivantes en exception :"
$iptables -N ALLOWED_IPs
for ip in ${ipExceptions} ; do
echo " - ${ip}"
$iptables -A ALLOWED_IPs -s ${ip} -j ACCEPT
done
## Autoriser le trafic dans la Chain
$iptables -A INPUT -j ALLOWED_IPs
$iptables -A OUTPUT -j ALLOWED_IPs
$iptables -A FORWARD -j ALLOWED_IPs
## Sortir de la chain
$iptables -A ALLOWED_IPs -j RETURN
else
echo "Aucune IP à ajouter en exception."
fi
#
# ============
# Block des IP
# ============
#
if [ ! -z "${ipBlocked}" ] ; then
echo "Autorisation des IP suivantes sur le port 443 seulement :"
for ip in ${ipBlocked} ; do
echo " - ${ip}"
$iptables -A INPUT -p tcp -s ${ip} --dport 443 -j ACCEPT
$iptables -A INPUT -s ${ip} -j LOG --log-prefix "[DROP][INPUT][IP ${ip} BLOCKED] "
$iptables -A INPUT -s ${ip} -j DROP
done
else
echo "Aucune IP à bloquer."
fi
# ===================
# Support de SSHguard
# ===================
#
iptables -n --list sshguard > /dev/null 2>&1
if [ $? -eq 0 ] ; then
echo "SSHGuard est déjà actif."
else
if [ ${sshguard} = true ] ; then
echo "Ajout de SSHGuard dans IPTables"
$iptables -N sshguard
$ip6tables -N sshguard
echo "Support de SSHGuard pour les ports suivants : ${SSHGUARD_PORTS}"
# Bloquer les IP sur tous les ports
if [ "${SSHGUARD_BLOCK_ALL}" = true ] ; then
# Bloquer les IP sur certains ports seulements
echo " - Les IP seront bloquées sur tous les ports."
$iptables -I INPUT -j sshguard
$ip6tables -I INPUT -j sshguard
else
echo " - Les IP seront bloquées sur les ports suivants : ${SSHGUARD_PORTS}"
$iptables -A INPUT -m multiport -p tcp --destination-ports ${SSHGUARD_PORTS} -j sshguard
$ip6tables -A INPUT -m multiport -p tcp --destination-ports ${SSHGUARD_PORTS} -j sshguard
fi
else
echo "SSHGuard ne sera pas supporté."
fi
fi
#
# ===========
# PROTECTIONS
# ===========
#
# while true; do
# read -p "Voulez-vous activer les règles de protection des attaques réseau courantes [O/N] ? " yn
# case "$yn" in
# y|y|O|o ) enableProtectRules=true ; break ;;
# n|N ) enableProtectRules=false ; break ;;
# * ) echo "Réponse non reconnue (O/N).";;
# esac
# done
echo ""
if [ ${enableProtectRules} = true ] ; then
echo "Ajout des règles de protection contre certaines tentatives d'attaques réseau."
## Drop des paquets invalides (sans logger)
$iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
$iptables -A FORWARD -m conntrack --ctstate INVALID -j DROP
$iptables -A OUTPUT -m conntrack --ctstate INVALID -j DROP
## Autoriser seulement les paquets SYN pour les nouvelles connexions
$iptables -A INPUT -p tcp ! --syn -m conntrack --ctstate NEW ${logDropLimit} -j LOG --log-prefix "[DROP][INPUT][NEW NOT SYN]" --log-level $logLevelDrop
$iptables -A INPUT -p tcp ! --syn -m conntrack --ctstate NEW ${logDropLimit} -j DROP
## Connexion max web (https://blog.meshup.net/se-proteger-des-attaques-de-type-http-flood-avec-ossec-et-iptables/)
$iptables -N HTTP-FLOOD
$iptables -I FORWARD -p tcp --syn --dport 80 -m connlimit --connlimit-above ${limitConn} -j HTTP-FLOOD
$iptables -I FORWARD -p tcp --syn --dport 443 -m connlimit --connlimit-above ${limitConn} -j HTTP-FLOOD
$iptables -A HTTP-FLOOD ${logDropLimit} -j RETURN
$iptables -A HTTP-FLOOD -m limit --limit 1/s -j LOG --log-prefix "[DROP][INPUT][HTTP FLOOD]" --log-level $logLevelDrop
$iptables -A HTTP-FLOOD -j DROP
## Limiter le Ping (Protection SMURF)
$iptables -A INPUT -p icmp -m icmp --icmp-type address-mask-request -j DROP
$iptables -A INPUT -p icmp -m icmp --icmp-type timestamp-request -j DROP
$iptables -A INPUT -p icmp -m limit --limit 1/s --limit-burst 1 -j ACCEPT
$iptables -A INPUT -p icmp -m limit --limit 1/s --limit-burst 1 -j LOG --log-prefix "[DROP][INPUT][PING FLOOD] " --log-level $logLevelDrop
$iptables -A INPUT -p icmp -j DROP
$iptables -A INPUT -p icmp --icmp-type echo-request -j DROP
## Protection contre SYN FLOOD avec SYNPROXY
## PROVOQUE DES ERREURS ?
#$iptables -t raw -A PREROUTING -p tcp -m tcp --syn -j CT --notrack
$iptables -A INPUT -p tcp -m tcp -m conntrack --ctstate INVALID,UNTRACKED -j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460
$iptables -A INPUT -m conntrack --ctstate INVALID -j LOG --log-prefix "[DROP][INPUT][SYN FLOOD] " --log-level $logLevelDrop
$iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
## Scan de port probable (Flags TCP improbables)
$iptables -N port-scanning
$iptables -A port-scanning -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s --limit-burst 2 -j RETURN
$iptables -A port-scanning -p tcp --tcp-flags SYN,ACK SYN,ACK -m conntrack --ctstate NEW -j RETURN
$iptables -A port-scanning -p tcp --tcp-flags SYN,FIN SYN,FIN -j RETURN
$iptables -A port-scanning -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j RETURN
$iptables -A port-scanning -p tcp --tcp-flags FIN,RST FIN,RST -j RETURN
$iptables -A port-scanning -p tcp --tcp-flags ACK,FIN FIN -j RETURN
$iptables -A port-scanning -p tcp --tcp-flags ACK,PSH PSH -j RETURN
$iptables -A port-scanning -p tcp --tcp-flags ACK,URG URG -j RETURN
$iptables -A port-scanning -p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j RETURN
$iptables -A port-scanning -p tcp --tcp-flags FIN,SYN FIN,SYN -j RETURN
$iptables -A port-scanning -p tcp --tcp-flags FIN,ACK FIN -j RETURN
$iptables -A port-scanning -p tcp --tcp-flags ALL FIN,PSH,URG -j RETURN
$iptables -A port-scanning -p tcp --tcp-flags ALL SYN,FIN,PSH,URG -j RETURN
$iptables -A port-scanning -p tcp --tcp-flags SYN,RST SYN,RST -j RETURN
$iptables -A port-scanning -p tcp --tcp-flags ALL ALL -j RETURN
$iptables -A port-scanning -p tcp --tcp-flags ALL NONE -j RETURN
$iptables -A port-scanning -p tcp --tcp-flags FIN,URG,PSH FIN,URG,PSH -j RETURN
$iptables -A port-scanning -p tcp --tcp-flags ALL FIN -j RETURN
$iptables -A port-scanning -p tcp --tcp-flags ALL URG,PSH,SYN,FIN -j RETURN
$iptables -A port-scanning -p tcp --tcp-flags ALL SYN,FIN -j RETURN
$iptables -A port-scanning -p tcp --tcp-flags ALL URG,PSH,FIN -j RETURN
$iptables -A port-scanning ${logDropLimit} -j LOG --log-prefix "[DROP][INPUT][PORT SCAN]" --log-level $logLevelDrop
$iptables -A port-scanning -j DROP
## SSH Bruteforce
$iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --set
$iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --update --seconds 60 --hitcount 10 ${logDropLimit} -j LOG --log-prefix "[DROP][INPUT][SSH BRUTEFORCE]" --log-level $logLevelDrop
$iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --update --seconds 60 --hitcount 10 -j DROP
## Bloquer les block MSS non communs
$iptables -t mangle -A PREROUTING -p tcp -m conntrack --ctstate NEW -m tcpmss ! --mss 536:65535 ${logDropLimit} -j LOG --log-prefix "[DROP][INPUT][UNCOMMON MSS]" --log-level $logLevelDrop
$iptables -t mangle -A PREROUTING -p tcp -m conntrack --ctstate NEW -m tcpmss ! --mss 536:65535 -j DROP
else
echo "Règles de protection contre certaines tentatives d'attaques désactivées."
fi
#
# ========================================================
# Limites de connexion parallèle par IP sur certains ports
# ========================================================
#
#
if [ ! -z "${limitConnTcpPorts}" ] ; then
echo "Limitation du nombre de nouvelle connexion TCP concurrente :"
for port in ${limitConnTcpPorts} ; do
echo " - Sur le port ${port}/TCP"
$iptables -A INPUT -p tcp -m conntrack --ctstate NEW --dport ${port} ${logDropLimit} -j DROP
done
else
echo "Aucune limitation des connexions parallèles en TCP."
fi
if [ ! -z "${limitConnUdpPorts}" ] ; then
echo "Limitation du nombre de nouvelle connexion UDP concurrente :"
for port in ${limitConnUdpPorts} ; do
echo " - Sur le port ${port}/UDP"
$iptables -A INPUT -p udp -m conntrack --ctstate NEW --dport ${port} ${logDropLimit} -j DROP
done
else
echo "Aucune limitation des connexions parallèles en UDP."
fi
#
# ======================================
# Autorisations et logs du flux autorisé
# ======================================
#
echo ""
## Ports ouverts en écoute (TCP)
if [ ! -z "${listenTcpPorts}" ] ; then
echo "[INPUT] Ouverture des ports TCP suivant :"
for port in ${listenTcpPorts} ; do
echo " - ${port}"
$iptables -A INPUT -p tcp -s 0/0 -d ${SERVER_IP} --dport ${port} -m conntrack --ctstate NEW ${logDropLimit} -j LOG --log-prefix "[ACCEPT][INPUT][PORT ${port}] " --log-level $logLevelAccept
$iptables -A INPUT -p tcp -s 0/0 -d ${SERVER_IP} --dport ${port} -m conntrack --ctstate NEW -j ACCEPT
# $iptables -A OUTPUT -p tcp --sport ${port} -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
done
fi
## Ports ouverts en écoute (UDP)
if [ ! -z "${listenUdpPorts}" ] ; then
echo "[INPUT] Ouverture des ports UDP suivant :"
for port in ${listenUdpPorts} ; do
echo " - ${port}"
$iptables -A INPUT -p udp -s 0/0 -d ${SERVER_IP} --dport ${port} -m conntrack --ctstate NEW ${logDropLimit} -j LOG --log-prefix "[ACCEPT][INPUT][PORT ${port}] " --log-level $logLevelAccept
$iptables -A INPUT -p udp -s 0/0 -d ${SERVER_IP} --dport ${port} -m conntrack --ctstate NEW -j ACCEPT
# $iptables -A OUTPUT -p udp --sport ${port} -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
done
fi
## Ports ouverts sortie (TCP)
if [ ! -z "${outTcpPorts}" ] ; then
echo "[OUTPUT] Ouverture des ports TCP suivant :"
for port in ${outTcpPorts} ; do
echo " - ${port}"
$iptables -A OUTPUT -p tcp --dport ${port} -m conntrack --ctstate NEW ${logDropLimit} -j LOG --log-prefix "[ACCEPT][OUTPUT][PORT ${port}] " --log-level $logLevelAccept
$iptables -A OUTPUT -p tcp --dport ${port} -m conntrack --ctstate NEW -j ACCEPT
# $iptables -A INPUT -p tcp -s 0/0 -d ${SERVER_IP} --sport ${port} -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
done
fi
## Ports ouverts sortie (UDP)
if [ ! -z "${outUdpPorts}" ] ; then
echo "[OUTPUT] Ouverture des ports UDP suivant :"
for port in ${outUdpPorts} ; do
echo " - ${port}"
$iptables -A OUTPUT -p udp --dport ${port} -m conntrack --ctstate NEW ${logDropLimit} -j LOG --log-prefix "[ACCEPT][INPUT][PORT ${port}] " --log-level $logLevelAccept
$iptables -A OUTPUT -p udp --dport ${port} -m conntrack --ctstate NEW -j ACCEPT
# $iptables -A INPUT -p udp -s 0/0 -d ${SERVER_IP} --sport ${port} -j ACCEPT
done
fi
# LOG DE LA CHAIN DOCKER
echo ""
echo "Logs du flux Docker."
# CHAIN DOCKER-USER si le service docker n'est pas encore démarré
$iptables -I DOCKER-USER ${logDropLimit} -j LOG --log-prefix "[ACCEPT][INPUT][DOCKER] " --log-level $logLevelAccept > /dev/null 2>&1
# CHAIN DOCKER si le service est déjà en fonctionnement
$iptables -I DOCKER ${logDropLimit} -j LOG --log-prefix "[ACCEPT][INPUT][DOCKER] " --log-level $logLevelAccept > /dev/null 2>&1
echo ""
#
# =========================
# Logs du flux non-autorisé
# =========================
#
$iptables -A INPUT ${logDropLimit} -j LOG --log-prefix="[DROP][INPUT] " --log-level $logLevelDrop
$iptables -A INPUT -j DROP
$iptables -A FORWARD ${logDropLimit} -j LOG --log-prefix="[DROP][FORWARD] " --log-level $logLevelDrop
$iptables -A FORWARD -j DROP
# Notifier aux utilisateurs locaux que le port en sortie est filtré
$iptables -A OUTPUT ${logDropLimit} -j LOG --log-prefix="[DROP][OUTPUT] " --log-level $logLevelDrop
$iptables -A OUTPUT -j REJECT
#
# ======================================
# Sauvegarder les règles après un reboot
# ======================================
#
echo ""
# Si les règles sont OK, demander s'il faut sauver les règles ou demander à l'utilisateur
while true; do
echo "Testez d'ouvrir une nouvelle connexion SSH en plus pour valider le fonctionnement !"
read -p "Voulez-vous sauvegarder la configuration actuelle en mode permanent [O/N] ou reset [R] ? " yn
case "$yn" in
y|y|O|o ) echo "Sauvegarde des règles pour persistance" ; service iptables save ; break ;;
n|N ) break;;
r|R ) echo "Annulation de toutes les règles" ; $iptables -P INPUT ACCEPT && $iptables -P OUTPUT ACCEPT && $iptables -F && $iptables -X ; break ;;
* ) echo "Réponse non reconnue (O/N/r).";;
esac
done
## On quitte pour terminer correctement
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment