Security Architecture Linux with IPV6 Part 2
Introduction / Einführung
Im ersten Teil haben wir uns mit Kernel Einstellungen und dem Konfigurieren von statischen Interfacen im Linux beschäftigt. Jetzt gehen wir weiter und erstellen ein Service welche uns immer die Firewall Regeln auf den Servern erzeugt nach dem Start des Servers.
In the first part we have dealt with kernel settings and the configuration of static interfaces in Linux. Now we go further and create a service which always generates the firewall rules on the servers after the server is started.
Sofern Sie nicht modernere Komponenten wie nftables1 (oder eBPF 😉 ) verwenden, filtern Linux-Server den IPv4-Datenverkehr mit iptables und den IPv6-Datenverkehr mit ip6tables. Wenn sich Ihre Serveradministratoren nicht für IPv6 interessieren, haben sie ip6tables wahrscheinlich nicht mit einer DENY ALL-Regel konfiguriert.
Unless you use more modern components such as nftables1 (or eBPF 😉 ), Linux servers filter IPv4 traffic with iptables and IPv6 traffic with ip6tables. If your server administrators are not interested in IPv6, they have probably not configured ip6tables with a DENY ALL rule.
vi /etc/iptables.rules
chmod +x /etc/iptables.rules
#!/bin/bash
IP6TABLES=/usr/sbin/ip6tables
IPTABLES=/usr/sbin/iptables
# Set Interface Name
export INTERFACE=("ens192")
# Set of trusted hosts to be allowed for some selective input traffic
export SSH_CLIENTS_V6=("2a02:238:0:0:250:56ff:fead:4f4a/128")
export SNMP_CLIENTS_V6=("2a02:238:0:0:250:56ff:fead:afbe/128")
export TRUSTED_HOSTS_V6=("2a02:238:0:0:250:56ff:fead:4f4a/128","2a02:238:0:300::1/128")
# Set of addresses of this host
export IPV4IP=("1.1.1.1")
export IPV6IP=("2a02:0:0:300::2/128")
export SSH_CLIENTS=("8.8.8.8")
export SNMP_CLIENTS=("7.7.7.7","8.8.8.8")
export MYSQL_CLIENTS=("2.2.2.2")
export HTTP_ADMIN_CLIENTS=("2.2.2.2")
case "$1" in
start)
### IPV6 ###
$IP6TABLES -P INPUT ACCEPT
$IP6TABLES -P OUTPUT ACCEPT
$IP6TABLES -P FORWARD ACCEPT
$IP6TABLES -F
#DROP MULTICAST TRAFFIC GOING TO ALL-NODES LINK-LOCAL
$IP6TABLES -I INPUT 1 -d ff02::1 -j DROP
#BLOCK EXTENSION HEADERS
$IP6TABLES -I INPUT 2 -i $INTERFACE -m ipv6header --header dst --soft -j DROP
$IP6TABLES -I INPUT 3 -i $INTERFACE -m ipv6header --header hop --soft -j DROP
$IP6TABLES -I INPUT 4 -i $INTERFACE -m ipv6header --header route --soft -j DROP
$IP6TABLES -I INPUT 5 -i $INTERFACE -m ipv6header --header frag --soft -j DROP
$IP6TABLES -I INPUT 6 -i $INTERFACE -m ipv6header --header auth --soft -j DROP
$IP6TABLES -I INPUT 7 -i $INTERFACE -m ipv6header --header esp --soft -j DROP
$IP6TABLES -I INPUT 8 -i $INTERFACE -m ipv6header --header none --soft -j DROP
# TYPE 135 AND 136
# ===========================
# Allow inbound Neighbor Solicitation – Type 135 Neighbor Advertisement – Type 136 only from predetermined hosts and only destined to (our) host address(es)
for trusted_host in ${TRUSTED_HOSTS_V6[@]}
do
for host_address in ${IPV6IP[@]}
do
$IP6TABLES -A INPUT -p icmpv6 -s $trusted_host -d $host_address --icmpv6-type 135 -j ACCEPT
$IP6TABLES -A INPUT -p icmpv6 -s $trusted_host -d $host_address --icmpv6-type 136 -j ACCEPT
done
done
# Allow outbound Neighbor Solicitation – Type 135 Neighbor Advertisement – Type 136
for host_address in ${IPV6IP[@]}
do
$IP6TABLES -A OUTPUT -p icmpv6 -s $host_address --icmpv6-type 135 -j ACCEPT
$IP6TABLES -A OUTPUT -p icmpv6 -s $host_address --icmpv6-type 136 -j ACCEPT
done
# ECHO REQUESTS AND REPLIES
# ===========================
# Allow inbound echo requests only from predetermined hosts and only destined to (our) host address(es)
for trusted_host in ${TRUSTED_HOSTS_V6[@]}
do
for host_address in ${IPV6IP[@]}
do
$IP6TABLES -A INPUT -p icmpv6 -s $trusted_host -d $host_address --icmpv6-type echo-request -m limit --limit 900/min -j ACCEPT
done
done
# Allow outbound echo requests
for host_address in ${IPV6IP[@]}
do
$IP6TABLES -A OUTPUT -p icmpv6 -s $host_address --icmpv6-type echo-request -j ACCEPT
done
# Allow incoming echo reply messages only for existing sessions
$IP6TABLES -A INPUT -m state -p icmpv6 --state ESTABLISHED,RELATED --icmpv6-type echo-reply -j ACCEPT
# Allow outgoing echo reply messages
for host_address in ${IPV6IP[@]}
do
$IP6TABLES -A OUTPUT -p icmpv6 -s $host_address --icmpv6-type echo-reply -j ACCEPT
done
# DESTINATION UNREACHABLE ERROR MESSAGES
# ======================================
# Allow incoming destination unreachable messages only for existing sessions
$IP6TABLES -A INPUT -m state -p icmpv6 --state ESTABLISHED,RELATED --icmpv6-type destination-unreachable -j ACCEPT
# PACKET TOO BIG ERROR MESSAGES
# =============================
# Allow incoming and outgoing Packet Too Big messages
$IP6TABLES -A INPUT -p icmpv6 --icmpv6-type packet-too-big -j ACCEPT
$IP6TABLES -A OUTPUT -p icmpv6 --icmpv6-type packet-too-big -j ACCEPT
# TIME EXCEEDED ERROR MESSAGES
# ============================
# Allow incoming time exceeded code 0 and 1 messages only for existing sessions
$IP6TABLES -A INPUT -m state -p icmpv6 --state ESTABLISHED,RELATED --icmpv6-type ttl-zero-during-transit -j ACCEPT
$IP6TABLES -A INPUT -m state -p icmpv6 --state ESTABLISHED,RELATED --icmpv6-type time-exceeded -j ACCEPT
# PARAMETER PROBLEM ERROR MESSAGES
# ================================
# Allow incoming parameter problem code 1 and 2 messages for an existing session
$IP6TABLES -A INPUT -m state -p icmpv6 --state ESTABLISHED,RELATED --icmpv6-type unknown-header-type -j ACCEPT
$IP6TABLES -A INPUT -m state -p icmpv6 --state ESTABLISHED,RELATED --icmpv6-type unknown-option -j ACCEPT
# DROP ANY OTHER ICMPV6 TRAFFIC
# =============================
$IP6TABLES -A OUTPUT -p icmpv6 -j DROP
$IP6TABLES -A INPUT -p icmpv6 -j DROP #Not actually required due to the default deny policy for INPUT chain
# Accepts all established inbound connections
$IP6TABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allows SSH connections
for CLIENT in ${SSH_CLIENTS_V6[@]}
do
$IP6TABLES -A INPUT -m state --state NEW -m tcp -p tcp -s $CLIENT -d $IPV6IP --dport 22 -j ACCEPT
done
# Allows SNMP for Management Stations
for CLIENT in ${SNMP_CLIENTS_V6[@]}
do
$IP6TABLES -A INPUT -p udp -m udp -s $CLIENT -d $IPV6IP --dport 161 -j ACCEPT
done
# Allows database connections
$IP6TABLES -A INPUT -p TCP -s ::1 -d ::1 --dport 953 -j ACCEPT
# Allows DNS from everywhere
$IP6TABLES -A INPUT -p udp -s ::/0 -d $IPV6IP --dport 53 -j ACCEPT
$IP6TABLES -A INPUT -p tcp -s ::/0 -d $IPV6IP --dport 53 -j ACCEPT
# log iptables denied calls (access via 'dmesg' command)
$IP6TABLES -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7
# Allows all outbound traffic
$IP6TABLES -A OUTPUT -j ACCEPT
# Reject all other inbound - default deny unless explicitly allowed policy:
$IP6TABLES -A INPUT -j DROP
$IP6TABLES -A FORWARD -j DROP
### IPV4 ###
$IPTABLES -P INPUT ACCEPT
$IPTABLES -P OUTPUT ACCEPT
$IPTABLES -P FORWARD ACCEPT
$IPTABLES -F
# Accepts all established inbound connections
$IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allow ping
$IPTABLES -A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
# Allows SSH connections
for CLIENT in ${SSH_CLIENTS[@]}
do
$IPTABLES -A INPUT -p tcp -s $CLIENT -d $IPV4IP -m state --state NEW --dport 22 -j ACCEPT
done
# Allow MySQL from external
for CLIENT in ${MYSQL_CLIENTS[@]}
do
$IPTABLES -A INPUT -p tcp -s $CLIENT -d $IPV4IP --dport 3306 -j ACCEPT
done
# Allows database connections
$IPTABLES -A INPUT -p TCP -s 127.0.0.1 -d 127.0.0.1 --dport 3306 -j ACCEPT
# Alloes HTTP to Admin Interface
for CLIENT in ${HTTP_ADMIN_CLIENTS[@]}
do
$IPTABLES -A INPUT -p tcp -s $CLIENT -d $IPV4IP --dport 8081 -j ACCEPT
done
# Allows SNMP for Management Stations
for CLIENT in ${SNMP_CLIENTS[@]}
do
$IPTABLES -A INPUT -p udp -s $CLIENT -d $IPV4IP --dport 161 -j ACCEPT
done
# Allows DNS from everywhere
$IPTABLES -A INPUT -p udp -s 0.0.0.0/0 -d $IPV4IP --dport 53 -j ACCEPT
$IPTABLES -A INPUT -p tcp -s 0.0.0.0/0 -d $IPV4IP --dport 53 -j ACCEPT
# log iptables denied calls (access via 'dmesg' command)
$IPTABLES -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7
# Allows all outbound traffic
$IPTABLES -A OUTPUT -j ACCEPT
# Reject all other inbound - default deny unless explicitly allowed policy:
$IPTABLES -A INPUT -j REJECT
$IPTABLES -A FORWARD -j REJECT
;;
stop)
$IPTABLES -F
$IPTABLES -P INPUT ACCEPT
$IPTABLES -P OUTPUT ACCEPT
$IP6TABLES -F
$IP6TABLES -P INPUT ACCEPT
$IP6TABLES -P OUTPUT ACCEPT
echo "iptables ruleset has been removed"
;;
restart)
$0 stop
$0 start
;;
*)
echo "Usage: $0 {start|stop|restart}"
esac
exit 0
Um diese Script jetzt als Dienst starten zu können, erstellen wir einen Service, den wir dann natürlich noch für den Start des Servers aktivieren.
To be able to start this script as a service, we create a service, which we then activate to start the server.
vi /etc/systemd/system/yourdaemon.service
[Unit]
Description=iptables firewalling ruleset loader
After=network.target
[Service]
Type=simple
ExecStart=/bin/bash /etc/iptables.rules start
ExecStop=/bin/bash /etc/iptables.rules stop
RestartSteps=/bin/bash /etc/iptables.rules restart
ExecReload=/bin/bash /etc/iptables.rules restart
RemainAfterExit=yes
TimeoutStartSec=0
[Install]
WantedBy=default.target
systemctl enable yourdaemon.service
Nun haben wir unseren Server bestmöglich geschützt und den Angriffsvektor eingeschränkt. Als Nächstes solltest du dich dann dem Code deines Dienstes widmen. Dort kann man im Code schwachstellen finden welche es dem Angreifer ermöglicht böse Sachen auf deinem Server auszuführen.
We have now protected our server in the best possible way and restricted the attack vector. Next, you should look at the code of your service. There you can find vulnerabilities in the code that allow the attacker to execute malicious things on your server.
Quellen / Sources:
- Linux Security Guide for Hardening IPv6
- Configuration for IPv6 ACLs
- Windows Security Guide for Hardening IPv6
- Operational Security Considerations for IPv6 Networks
AIPOST