Skip to main content

Simple Firewall, Port Knocking and DDoS Testing

Take care

Please do not run this if you don't understand it. I don't take any responsibility for losing access to your servers because of a too tight firewall rules.

iptables with bash

#!/bin/bash
### BEGIN INIT INFO
# Provides: Simple Firewall for iptables
# Required-Start: $local_fs $remote_fs $network
# Required-Stop: $local_fs $remote_fs $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: start/stop/restart/status iptables-firewall
### END INIT INFO

# Modified by Teo
# Initial Author: Marian Amza.
# $ sudo nano /etc/init.d/fw
# $ sudo chmod +x /etc/init.d/fw
# $ sudo update-rc.d fw defaults
# $ sudo /etc/init.d/fw start
#####

# Custom Variables
IPT="iptables"
PORT_SSH="4422"

# Class for MASQUERADE
MASQ="10.10.10.0/24"

# User have the sudo rights?
fw_check() {
if [ "$(id -u)" != "0" ]; then
echo "You need to be root for using this script."
exit 1
fi
return 0
}

# Remove all rules from iptables
fw_clear() {
echo "Removing rules from iptables..."
tables="filter nat mangle"
for tables in ${table}
do
${IPT} -F -t ${table}
${IPT} -X -t ${table}
# Reset iptables counters
${IPT} -Z -t ${table}
done

# Policy ACCEPT to all packets
echo "All packets have policy ACCEPT..."
${IPT} --policy INPUT ACCEPT
${IPT} --policy OUTPUT ACCEPT
${IPT} --policy FORWARD ACCEPT

return 0
}

# Start Firewall
fw_start() {
fw_clear

# Policy default DROP all packets. Paranoid Mode - Whitelist.
${IPT} --policy INPUT DROP
${IPT} --policy OUTPUT DROP
${IPT} --policy FORWARD DROP

# Kernel
# Drop ICMP echo-request messages sent to broadcast or multicast addresses
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
# Don't accept ICMP redirect messages
echo 0 > /proc/sys/net/ipv4/conf/all/accept_redirects
# Don't send ICMP redirect messages
echo 0 > /proc/sys/net/ipv4/conf/all/send_redirects
# Drop source routed packets
echo 0 > /proc/sys/net/ipv4/conf/all/accept_source_route
# Enable TCP SYN cookie protection from SYN floods
echo 1 > /proc/sys/net/ipv4/tcp_syncookies
# Enable source address spoofing protection
echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter
# Log packets with impossible source addresses (spoofing)
echo 1 > /proc/sys/net/ipv4/conf/all/log_martians
# Enable IP Forward
echo 1 > /proc/sys/net/ipv4/ip_forward

# General permissions
# Allow traffic to 127.0.0.1 (localhost)
${IPT} -I INPUT -d 127.0.0.0/8 -j ACCEPT
${IPT} -I OUTPUT -s 127.0.0.0/8 -j ACCEPT
# Allow established traffic
${IPT} -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
${IPT} -I OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
${IPT} -I FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

# Services
# Accept all OUTPUT (reverse shell?)
${IPT} -I OUTPUT -p all -j ACCEPT
# SSH
${IPT} -I INPUT -p tcp --dport ${PORT_SSH} -j ACCEPT

# OpenVZ
# Masquerade
for NET in ${MASQ}
do
${IPT} -t nat -A POSTROUTING -s ${NET} -o vmbr0 -j MASQUERADE
done
${IPT} -A FORWARD -i vmbr0 -o vmbr1 -m state --state RELATED,ESTABLISHED -j ACCEPT
${IPT} -A FORWARD -i vmbr1 -o vmbr0 -j ACCEPT

# DROP invalid or malformation packets
# Check TCP Flags
# Flags are: SYN ACK FIN RST URG PSH : ALL NONE
# NULL Packets || No TCP Flags
${IPT} -I INPUT -p tcp --tcp-flags ALL NONE -j DROP
# Stop Xmas Tree type scanning
${IPT} -I INPUT -p tcp --tcp-flags ALL ALL -j DROP
${IPT} -I INPUT -p tcp --tcp-flags ALL URG,ACK,PSH,RST,SYN,FIN -j DROP
# NMAP Xmas Scan
${IPT} -I INPUT -p tcp --tcp-flags ALL URG,PSH,FIN -j DROP
# NMAP ID
${IPT} -I INPUT -p tcp --tcp-flags ALL URG,PSH,SYN,FIN -j DROP
# NMAP FIN/URG/PSH
${IPT} -I INPUT -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP
# SYN-FIN Scan
${IPT} -I INPUT -p tcp --tcp-flags ALL SYN,FIN -j DROP
# FIN Scan
${IPT} -I INPUT -p tcp --tcp-flags ALL FIN -j DROP
# pscan
${IPT} -I INPUT -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP
# SYN/RST
${IPT} -I INPUT -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
# SYN/FIN || pscan 2
${IPT} -I INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
# FIN/RST || pscan 2
${IPT} -I INPUT -p tcp --tcp-flags FIN,RST FIN,RST -j DROP
# FIN without ACK
${IPT} -I INPUT -p tcp --tcp-flags ACK,FIN FIN -j DROP
# PSH without ACK
${IPT} -I INPUT -p tcp --tcp-flags ACK,PSH PSH -j DROP
# URG without ACK
${IPT} -I INPUT -p tcp --tcp-flags ACK,URG URG -j DROP

# Fragments Packets
${IPT} -I INPUT -p tcp -f -j DROP
# Bad Packets
${IPT} -I INPUT -p tcp -m state --state INVALID -j DROP
${IPT} -I FORWARD -p tcp -m state --state INVALID -j DROP
${IPT} -I OUTPUT -p tcp -m state --state INVALID -j DROP
# Check SYN Packets
${IPT} -I INPUT -p tcp ! --syn -m state --state NEW -j DROP

echo "Firewall Started!"
return 0
}

# Stop Firewall
fw_stop() {
fw_clear
echo "Firewall Stopped!"
return 0
}

# Status Firewall
fw_status() {
tables="filter nat mangle"
for tables in ${table}
do
echo "$table table: "
${IPT} -t $table -L -v
done
return 0
}

# MAIN
case "${1}" in
start)
fw_check
fw_start
;;
stop)
fw_check
fw_stop
;;
restart)
fw_check
fw_stop
fw_start
;;
status)
fw_check
fw_status
;;
version)
echo "Version: 1.0"
;;
*)
echo "Use: ${0} {start|stop|restart|status}"
exit 1
;;
esac

exit 0

Port Knocking

This is useful if you don't want to have any ports open on your servers.

# Create chains
iptables -N KNOCKING
iptables -N GATE1
iptables -N GATE2
iptables -N GATE3
iptables -N PASSED

# Direct incoming traffic to the KNOCKING chain
iptables -A INPUT -j KNOCKING

# Define rules for GATE1
iptables -A GATE1 -p tcp --dport 1111 -m recent --name AUTH1 --set -j DROP
iptables -A GATE1 -j DROP

# Define rules for GATE2
iptables -A GATE2 -m recent --name AUTH1 --remove
iptables -A GATE2 -p tcp --dport 2222 -m recent --name AUTH2 --set -j DROP
iptables -A GATE2 -j GATE1

# Define rules for GATE3
iptables -A GATE3 -m recent --name AUTH2 --remove
iptables -A GATE3 -p tcp --dport 3333 -m recent --name AUTH3 --set -j DROP
iptables -A GATE3 -j GATE1

# Define rules for PASSED
iptables -A PASSED -m recent --name AUTH3 --remove
iptables -A PASSED -p tcp --dport 22 -j ACCEPT
iptables -A PASSED -j GATE1

# Allow SSH connection within 30 seconds after completing the knocking sequence
iptables -A KNOCKING -m recent --rcheck --seconds 30 --name AUTH3 -j PASSED

# Allow 10 seconds to hit all gates in sequence
iptables -A KNOCKING -m recent --rcheck --seconds 10 --name AUTH2 -j GATE3
iptables -A KNOCKING -m recent --rcheck --seconds 10 --name AUTH1 -j GATE2

# If no valid sequence is detected, drop the traffic
iptables -A KNOCKING -j GATE1

DDoS Testing (simulate)

Simulating DDoS attacks (TCP, UDP, ICMP) with BoNeSi by spoofing many IPs in order to study how the attacks looks like.

  • Source Code: https://github.com/markus-go/bonesi

  • Demo: https://madm.dfki.de/projects/netcentricsecurity

  • Requirements:

    • 2 Servers in LAN or Virtualized.
    • In one of the servers you can install an nginx or apache.
    • In the othe server we will need to install BoNeSi.
      • libnet1-dev libpcap-dev
      • https://github.com/Markus-Go/bonesi
      • ./configure && make
      • cp src/bonesi .
    • Tests:
      • SYN spoofed (tcp attack): ./bonesi --ips=50k-bots --protocol=tcp -d eth0 10.0.0.8:80
      • UDP spoofed: ./bonesi --ips=50k-bots --protocol=udp -d eth0 10.0.0.8:80
      • ICMP spoofed (echo request): ./bonesi --ips=50k-bots --protocol=icmp -d eth0 10.0.0.8:80

SYN Flood - Linux

  • vnstat: Monitoring for bandwidth.
  • htop: Monitoring similar with top on the resources like CPU, RAM, Bandwidth.
  • tcpdump: Monitoring the network packets and can export the dump of the traffic (grep friendly)
  • modprobe/rmmod: Add or remove kernel modules that are required for a high-usage monitoring.
  • ethtool: Information about network interfaces.

What is a SYN Flood attack?

Method of Denial of Service (DoS) that affects the servers where TCP services are running. This is exploting the waiting mechanism that is implement in the TCP protocol, technique that after a packet is received with the SYN flag set as true to a port that is in LISTEN mode. If we send a lot of packets like this, the server can't handle those connections anymore and will start to fail - more details can be found in RFC4987.

The service will stay in SYN_RECV - so will be waiting after the clients to close those connections (ACK flag), but that won't happen. Standard transmission should have been: SYN -> SYN/ACK (this can't be sent back as the client was spoofing the client IP) -> ACK (of course this doesn't happen as the client doesn't know about these packets and they will be dropped). https://www.cisco.com/web/about/security/images/csc_child_pages/white_papers/ddos_fig07.jpg

How to detect the connections that are in SYN_RECV

  • sudo netstat -anutp | grep SYN_RECV | wc -l

If the number is quite big, then there is a good chance to have an ongoing attack.

  • sudo vnstat -l -i eth0

Check the bandwidth.

  • sudo tcpdump -i eth0 -nn 'tcp port 80' and 'tcp[13] == 2' -c 250

Monitoring first 250 packets.

How to protect via SynCookies

  • Basically the server will still reply with SYN/ACK, but won't add this answer in the queue, but instead will reconstruct the things later one based on the ACK packet.
  • Check if syncookies is active: sysctl -n net.ipv4.tcp_syncookies | cat /proc/sys/net/ipv4/tcp_syncookies
  • Activate the syncookies: echo "net.ipv4.tcp_syncookies = 1" >> /etc/sysctl.conf | sysctl -p
  • If the attack is not spoofing the IP, then it may be a good chance to block the attack with iptables.
    • sudo iptables -A INPUT -p tcp -m state --state NEW -m recent --update --seconds 60 --hitcount 30 -j DROP sudo iptables -A INPUT -p tcp -m state --state NEW -m recent --set -j ACCEPT