You are on page 1of 14

Configuring IPTABLES for Snort-Inline by Tim Slighter

January 23, 2003

Brief background on Snort-Inline Snort-Inline is more or less a snort binary that can be configured to receive specific input from IPTABLES. The key syntax used with IPTABLES is QUEUE. QUEUE instructs IPTABLES to pass any matching protocol traffic to the ip_queue module. Snort-Inline processes the matching traffic that has been passed to ip_queue and determines response based upon the configuration file (snort.conf) and rules files. This document is for instructions on how to get Snort-Inline working with IPTABLES. First assuming the user has working knowledge of Redhat, IPTABLES and Snort, this procedure has been tested with Redhat 7.3 Kernel 2.4.18-3. Lets break this paper down into logical sections: Determining what packages and RPM's are required Obtaining all required packages and RPM's Configuring and compiling required RPM's and source code Configuring your rc.firewall script Configuring and compiling Snort-Inline Test run your new project Understanding and working with the results Security considerations Please note that the rc.firewall script has been provided by Rob McMillen <mailto:rvmcmil@cablespeed.com> through the generosity of Honeynet.org (http://www.honeynet.org/papers/honeynet). The rc.firewall script provided in this paper has been edited in order to work with Snort-Inline and IPTABLES for a functional Intrusion Response System.

Determining what packages and RPM's are required


For the scope and purpose of this document, rc.firewall will be run in "Nat" mode. Snort-Inline will also be required for this implementation. Honeynet.org provides a Snort-Inline startup script that is very useful. If anyone is interested in running in Bridge mode, please visit the Honetnet.org website for tools and scripts.

Obtaining all required packages and RPM's

Unless the source RPM for IPTABLES has been previously built into the kernel, the standard IPTABLES RPM will not work correctly with Snort-Inline. The required RPM can be obtained from Netfilter.org @ http://www.netfilter.org/downloads.html 1.2.7a. Locate the file iptables-1.2.7a.tar.bz2 and download it. Snort-Inline can be located and downloaded from the Snort.org site @ http://www.snort.org/dl/contrib/patches/inline/ as file "snort-inline.tgz". Or simply go to http://www.snort.org/ and click on "downloads" - "contrib" - "patches" - "inline". The Honeynet provided startup script as well as other tools for Snort-Inline are available at http://www.honeynet.org/papers/honeynet/tools/. Make sure to grab the snort-inline startup script!

Configuring and compiling required RPM's and source code


Unpack the iptables-1.2.7a.tar.bz2 using bunzip2 and change into the newly created directory. Refer to the INSTALL file to correctly install the new IPTABLES source code. In the event that this file is not found, use the brief instructions below to compile the IPTABLES source code:

FOLLOW THESE STEPS:

1) Next, make the package. % make KERNEL_DIR=<<where-you-built-your-kernel>> 2) Finally, you need to install the shared libraries, and the binary: # make install KERNEL_DIR=<<where-you-built-your-kernel>> If you are a developer, you can install the headers, development libraries and associated development man pages, with: # make install-devel That's it! the KERNEL_DIR variable should most likely be /usr/src/linux-2.4. In the event there are issues compiling this source code, refer to the Netfilter.org website for support.

Configuring your rc.firewall script


Configuring the rc.firewall script is fairly straight forward but can be edited to meet any requirements. The main entries that need to edited are briefly shown below: COMMON VARS section MODE="nat" Use this mode unless your system is operating as a router for other systems with address translation PUBLIC_IP=""

This can be set to an IP address provided for either a virtual interface or an external interface not being used. Not important but something might need to be entered here. INET_IFACE="" This should be the ifconfig variable of the external interface. Do NOT use the same value for this and the LAN_IFACE value or the script will not run. If you do not have second interface, create a virtual interface eth0:1 and use that variable. This value does not affect Snort-Inline but is required for this script to function In this script PUBLIC_IP and INET_IFACE can probably be left empty LAN_IFACE="" This value will be the same that Snort-Inline will be running on. Commonly "eth0" is the value LAN_IP_RANGE="" IP Range of internal network (192.168.1.0 or according to the class subnet used)

LAN_BCAST_ADRESS="" Broadcast address according to the subnet used

################# All LAN fields MUST have an entry #################### QUEUE="yes" This must be set to "YES" for snort-inline to work

VARIABLES FOR NAT MODE section ALIAS_MASK="255.255.255.0" Set this according to subnet being used HPOT_IP="" This will be the IP address of the interface you are running Snort-Inline on. Stealth will NOT work here. SPECIAL CONSIDERATION VARIABLE section DNS_HOST="" If DNS is required, then enter the IP address of the system you are running SnortInline on here DNS_SVRS="" If DNS is required, then the IP address of the DNS server must be entered here The rc.firewall script also contains entries taking advantage of -j LOG for IPTABLES. Log level 6 defaults to info and will appear in /var/log/messages

according to the log-prefix that is used. If these LOG entries do not appear in the /var/log/messages file, check /etc/syslog.conf to ensure that *.info is present and logging to /var/log/messages This script will hopefully be available on the Snort website. For the time being, the script is available at the end of the document.

Configuring and compiling Snort-Inline


Tar xzf the "snort-inline.tgz" file and change into the "snort-inline" directory. Issue the command "./configure --enable-inline" in order to build for inline. Follow this with a "make" and "make install". In order to simplify the process run the configure script as "./configure --prefix=/usr/local/snort --enable-inline" or there will be some minor editing waiting for you later on. In the event that configure was run without the -prefix, issue a "cp -R snort-inline /usr/local/snort" and cd to /usr/local/snort/etc and begin edits on the snort.conf file. Much like the original snort, edit this file according to the vars, preprocessors and rules that meet your requirements. This process should be simple enough to not require any further documentation. The next step is to alter all of the rules files. cd to ../rules and either open and edit each rules file that will be used or take advantage of sed and some programming skills to perform a "global" search and replace on the all of the rules files. For the purpose of this document, the proper editing of one rules file will provide a sound starting point. For example, vi the scan.rules files and issue the following command ":1,%s/alert/drop/g" and enter and this should globally replace all occurrences of "alert" with "drop". Do the same to each rules file that will be used as specified in the snort.conf file. Providing that the snort-inline startup script was downloaded from Honeynet.org, "cp" this file to /etc/init.d and edit it according to where the directories and binaries are located. Ensure that ALL instances of eth* are changed to reflect the interface that snort-inline will be running on. The bottom line of the script should look something close to what is shown below: $SNORT -D -d -c /usr/local/snort/etc/snort.conf -Q -i eth0 -l $DIR/$DATE As always, prior to running this issue a "mkdir /var/log/snort". The first time running snort-inline may generate an error and the program will stop. A quick easy workaround to get rid of this problem is to edit the snort-inline startup script and place the following entry at the top of the file "/sbin/modprobe ip_queue". Finally, copy the script to a location where snort-inline can be started automatically "cp snortinline.sh /etc/init.d/snort" and chmod +x to make it executable.

Test run your new project


With the snort-inline script configured according to requirements and the rc.firewall in place with a chmod +x in /etc/init.d. Start the rc.firewall script issuing "/etc/init.d/rc.firewall". Uncomment the "set -x" line in the rc.firewall script for verbose debugging if there are problems. Follow this by starting the snort-inline script "/etc/init.d/snort". Issue a ps -ef to ensure that snort-inline is running as anticipated. Check for a new $DATE directory created in /var/log/snort that will be created when

snort-inline initializes.

Understanding and working with the results


Find a hub or switch and connect the system running snort-inline on the same network with a system that can run nmap and other pen-test oriented tools. Initially, running nmap -sF -sX -sN -sS and -sT scans will most likely return results the first few times. Continue running the scans and timeouts will start taking place. Conduct other tests that are known to fire alerts on snort signatures and observe the results. In our lab, the success rate for snort-inline responding with a "drop" was around 80% when scanning a single host. When enough scans were conducted to generate timeouts, subsequent success rates were over 90%. Conduct tests in accordance with what would normally take place from an external scan on your environment.

Security considerations
In order to further secure a snort-inline system, edit the rc.firewall script or create your IPTABLES that enhances restrictions on the INPUT table, such that the INPUT table becomes IPTABLES -P INPUT DROP. Originally setting the INPUT table to ACCEPT allows all traffic to pass through primarily for testing purposes. Feel free to edit the rc.firewall script to meet the needs of your organization.

rc.firewall script

#!/bin/bash # # rc.firewall, ver 0.6 - 5 Jan 2003 # http://www.honeynet.org/papers/honeynet/tools/ # Rob McMillen <rvmcmil@cablespeed.com> # This scripts has been borrowed from honeynet.org and customized for strict control of IPTABLES in conjunction with Snort-Inline # # PURPOSE # # This scripts has been redesigned for use with IPTABLES and Snort-Inline specifically. Use IPTABLES to specify # what traffic is analyzed, logged, or QUEUED. The primary method to deploy a working and successful IPTABLES # is by placing allowed hosts, services, traffic etc at the beginning of the chain, followed by j LOG and finally -j QUEUE # This will vary according to environment and requirements for each organization. Make note that anything used with -j QUEUE # will pass everything in that IPTABLES rule to Snort-Inline. Providing that all snort rules have "drop" in place of "alert" # the specific traffic will ONLY be blocked providing it meets any of the criteria in any of

the snort rules. In many situations # it would be recommendable to place -j QUEUE at the top of the IPTABLES chain but run the risk of the traffic being dropped # since it will not match any criteria in the IPTABLES chain or Snort-Inline. Use your own judgment according to the requirements # of your organization. # # REQUIREMENTS # This utility will not work with a standard IPTABLES RPM, one must compile the source RPM or the best solution would be to download # the most recent source from Netfilter.org. The Tarball from Netfilter contains INSTALL and README files on how to recompile your # new IPTABLES into the kernel. Providing that works well for you, then you should be able to proceed with this script with no issues. # # In order for the genII script to work, your kernel must # be compiled with bride and bridge firewall support. # Red Hat kernel 2.4.18-3 has this by default, most other # kernels do not. If yours does not, you will most likely # need to patch and recompile your kernel. You can find the # patch at # http://bridge.sourceforge.net/download.html # # You will also need bridge utilities to allow this script to # enable/configure bridging. I used bridge-utils-0.9.3-4 during # the testing of this script. # # # INSTALLATION # Once you have configured the variables of this script, you # simply execute this script. It calls on IPTables and # does everything for you (nice, huh? :). You must have IPTables # installed on your system, and kernel version 2.4.x. # # # MODE is the mode the firewall will use to operate. There are # two possible values at this time: nat, bridge. "nat" is GenI # where your gateway is routing in layer3. "bridge" is GenII # where your gateway is bridging in layer2. Of these two # options, "bridge" is the preferred, more secure MODE. # # MODE="nat" In this mode, the firewall will translate each ip # in the PUBLIC_IP variable to each ip in the HPOT_IP variable. # Order is important, so make sure you place the ips in the # variables as you would like them translated. For example, # PUBLIC_IP="192.168.1.1 192.168.1.2 192.168.1.3" # HPOT_IP="192.168.0.1 192.168.0.2 192.168.0.3" # # will translate as follows: # 192.168.1.1 => 192.168.0.1

# 192.168.1.2 => 192.168.0.2 # 192.168.1.3 => 192.168.0.3 # # Each variable is a space delimited list; therefore, you can have # as many as you want (or as many as an interface can have aliases). # # The following variables must match the setting for the translated # network. In the example above, they would be the settings of the # 192.168.0.* network # # LAN_IP_RANGE="192.168.0.0/24" # LAN_BCAST_ADDRESS="192.168.0.255" # # MODE="bridge" This mode should not be used unless your system is acting as a router without address translation. # In this mode, the firewall will act as a bridge, # bridging and bridge firewalling will need to be compiled into the # kernel. Default kernel for Redhat 7.3 (2.4.18-3) has it, but its # upgrade does not. All other default kernels do not support IPtables # in bridging mode. Therefore, your bridge will allow everything in and # everything out, completely bypassing your firewall rules. # # The following variables must match the settings for the bridged # network. If both sides of the bridge are on 10.0.0.*, # # LAN_IP_RANGE="192.168.1.0/24" # LAN_BCAST_ADDRESS="192.168.1.255" # # # NOTE: A quick check to ensure you have the LAN variables correct # is to check /var/log/messages. If you see logs stating # SPOOFED SOURCE, you probably have them set wrong. Also, # make sure your Honeypot default gateway is set to the # firewall internal interface when in nat mode and the # border router or routing device when in bridge mode.

#### If you want to see all the commands or which command is giving your # problems, remove the comment below. #set -x

#************************************************************************* # USER VARIABLE SECTION #************************************************************************* ############### # COMMON VARS # ###############

# The MODE variable tells the script to #setup a bridge HoneyWall # or a NATing HoneyWall. MODE="nat" #MODE="bridge" # A space delimited list of honeypots IPs (public IP) # If you are in "bridge" mode, this is the list of your # honeypot IP's that will be behind the bridge. If you are # in "nat" mode, this is the list of public IPs you will # be using for IP address translation. Still confused? Its # the list of IPs the hackers will attack. PUBLIC_IP="" ### Variable for external network INET_IFACE="" # This should be the ifconfig variable of the external interface. Do NOT use the same value for this # and the LAN_IFACE value or the script will not run. If you do not have second interface, create # a virtual interface eth0:1 and use that variable. This value does not affect Snort-Inline but is # required for this script to function ### Variables for internal network LAN_IFACE="" # This value will be the same that Snort-Inline will be running on. Commonly "eth0" is the value LAN_IP_RANGE="" # IP Range of internal network (192.168.1.0 or according to the class subnet used) LAN_BCAST_ADRESS="" # IP Broadcast range for internal network ### IPTables script can be used with the Snort-Inline filter ### You can find the current release at ### http://www.snort.org/dl/contrib/patches/inline/ QUEUE="yes" # This must be set to "yes" or Snort-Inline will not work as anticipated #QUEUE="no" # Do not use experimental QUEUE support ### Set the connection outbound limits for different protocols. SCALE="hour" # second, minute, hour, etc. TCPRATE="9" # Number of TCP connections per $SCALE UDPRATE="20" # Number of UDP connections per $SCALE ICMPRATE="50" # Number of ICMP connections per $SCALE OTHERRATE="10" # Number of other IP connections per $SCALE ###################### # END OF COMMON VARS # ###################### ########################## # VARIABLES FOR NAT MODE # ########################## # You use these variables ONLY if you are using NAT mode.

# If you are in bridging mode, then these variables will # not be used. # ALIAS_MASK="255.255.255.0" # Network mask to be used alias (This value can be changed according to your subnet mask) HPOT_IP="" # This will be the IP address of the interface you are running Snort-Inline on. Stealth will NOT # work here. ############################# # END OF NAT MODE VARIABLES # #############################

################################## # SPECIAL CONSIDERATION VARIABLE # ################################## # You may want to allow unrestricted outbound DNS access. # If you want to restrict the hosts that can access public dns servers, # set the DNS_HOST variable to the ip of the honeypots allowed to # make queries. Otherwise, leave it blank and the proper set of # ips will be assigned in order to allow all of your honeypots to # make dns queries. DNS_HOST="" # If you require DNS, then enter the IP address of the system you are running Snort-Inline on here # List of DNS servers your honeypot(s) are allowed to go to. # This is once a gain a space delimited list. DNS_SVRS="" # If you require DNS then the IP address of the DNS server must be entered here

########################################################## # VARIABLES THAT RESTRICT WHAT THE FIREWALL CAN SEND OUT # ########################################################## # This variable will limit outbound Firewall connections # to ports identified in the ALLOWED_TCP_OUT and # ALLOWED_UDP_OUT variables. If set to yes, it will # restrict the firewall. If set to no, it will allow all # outbound connections generated by the firewall. # NOTE: There must be a management interface in bridge # mode in order to have a firewall interface to restrict. #RESTRICT="yes" RESTRICT="no" # DO NOT USE this option!!

ALLOWED_UDP_OUT="53 123" ALLOWED_TCP_OUT="22 80 21" ########################## # END RESTRICT VARIABLES # ########################## ############################################ # LOCATION OF PROGRAMS USED BY THIS SCRIPT # ############################################ IPTABLES="/sbin/iptables" BRIDGE="/usr/sbin/brctl" IFCONFIG="/sbin/ifconfig" ROUTE="/sbin/route" MODPROBE="/sbin/modprobe" LSMOD="/sbin/lsmod" #################### # END OF PROG VARS # #################### #************************************************************************* # END OF USER VARIABLE SECTION (DO NOT EDIT BEYOND THIS POINT) #************************************************************************* ######### # First, confirm that IPChains is NOT running. If # it is running, clear the IPChains rules, remove the kernel # module, and warn the end user. /sbin/lsmod | grep ipchain IPCHAINS=$? if [ "$IPCHAINS" = 0 ]; then echo "" echo "Dooh, IPChains is currently running! IPTables is required by" echo "the rc.firewall script. IPChains will be unloaded to allow" echo "IPTables to run. It is recommened that you permanently" echo "disable IPChains in the /etc/rc.d startup scripts and enable" echo "IPTables instead." ipchains -F rmmod ipchains fi ######### # Flush rules # $IPTABLES -F $IPTABLES -F -t nat $IPTABLES -F -t mangle

$IPTABLES -X echo "" # Let's figure out dns if [ $DNS_HOST -z ] then if [ $MODE = "bridge" ] then DNS_HOST=$PUBLIC_IP else DNS_HOST=$HPOT_IP fi fi

######### # Load all required IPTables modules # ### Needed to initially load modules /sbin/depmod -a ### Add iptables target LOG. $MODPROBE ipt_LOG ### Add iptables QUEUE support (Experimental) if test $QUEUE = "yes" then # Insert kernel mod $MODPROBE ip_queue # check to see if it worked, if not exit with error $LSMOD | grep ip_queue IPQUEUE=$? if [ "$IPQUEUE" = 1 ]; then echo "" echo "It appears you do not have the ip_queue kernel module compiled" echo "for your kernel. This module is required for Snort-Inline and" echo "QUEUE capabilities. You either have to disable QUEUE, or compile" echo "the ip_queue kernel module for your kernel. This module is part" echo "of the kernel source." exit fi echo "Enabling Snort-Inline capabilities, make sure Snort-Inline is" echo "running in -Q mode, or all outbound traffic will be blocked" fi

### Support for connection tracking of FTP and IRC. $MODPROBE ip_conntrack_ftp $MODPROBE ip_conntrack_irc ### Enable ip_forward echo "1" > /proc/sys/net/ipv4/ip_forward

############################### ####IPTABLES ENTRIES########### ###############################

# Set up the new policy on the IPTABLES INPUT chain. Use ACCEPT first to make sure that everything works and then lock this down later $IPTABLES -P INPUT ACCEPT $IPTABLES -P FORWARD DROP $IPTABLES -P OUTPUT ACCEPT # Start off on the INPUT table and allow anything back in that was originated from your system $IPTABLES -A INPUT -i $LAN_IFACE -p all -m state --state ESTABLISHED, RELATED -j ACCEPT # Allow all Traffic on your loopback interface $IPTABLES -A INPUT -i lo -p all -j ACCEPT $IPTABLES -A OUTPUT -o lo -j ACCEPT # This might be a good time to pass all incoming traffic over to Snort $IPTABLES -A INPUT -i $LAN_IFACE -p all -j QUEUE # USE these lines below if you need to log every protocol that is coming into your system. This can be disk and resource intensive!! ### Inbound TCP $IPTABLES -A INPUT -i $LAN_IFACE -p tcp -m state --state NEW -j LOG --log-level 6 -log-prefix "INBOUND TCP: " $IPTABLES -A INPUT -i $LAN_IFACE -p tcp -m state --state NEW -j ACCEPT ### Inbound UDP $IPTABLES -A INPUT -i $LAN_IFACE -p udp -m state --state NEW -j LOG --log-level 6 -log-prefix "INBOUND UDP: " $IPTABLES -A INPUT -i $LAN_IFACE -p udp -m state --state NEW -j ACCEPT ### Inbound ICMP $IPTABLES -A INPUT -i $LAN_IFACE -p icmp -m state --state NEW -j LOG --log-level 6 --log-prefix "INBOUND ICMP: " $IPTABLES -A INPUT -i $LAN_IFACE -p icmp -m state --state NEW -j ACCEPT

### Inbound anything else $IPTABLES -A INPUT -i $LAN_IFACE -m state --state NEW -j LOG --log-level 6 --logprefix "INBOUND OTHER: "

# Okay, this is where the magic all happens. All outbound traffic is counted, # logged, and limited here. Targets (called Handlers) are what actually limit # the connections. All 'Handlers' are defined at the bottom of the script. # Egress filtering, don't want to let our compromised honeypot send spoofed packets. # Stops most outbound DoS attacks. However, we might want to allow our honeypots to # use dhcp to get an ip while in bridge mode. if [ $MODE = "bridge" ] then $IPTABLES -A OUTPUT -i $LAN_IFACE -p udp -s $LAN_IP_RANGE --sport 68 -d 255.255.255.255 --dport 67 -j LOG --log-level 6 --log-prefix "DHCP OUT REQUEST: " $IPTABLES -A OUTPUT -i $LAN_IFACE -p udp -s $LAN_IP_RANGE --sport 68 -d 255.255.255.255 --dport 67 -j ACCEPT fi $IPTABLES -A OUTPUT -i $LAN_IFACE -s ! $LAN_IP_RANGE -j LOG --log-level 6 -log-prefix "SPOOFED SOURCE: " $IPTABLES -A OUTPUT -i $LAN_IFACE -s ! $LAN_IP_RANGE -j DROP ### DNS / NTP Perhaps one of your honeypots needs consistent ### outbound access to provide internal service. for srvr in ${DNS_SVRS}; do for host in ${DNS_HOST}; do $IPTABLES -A OUTPUT -p udp -i $LAN_IFACE -s ${host} -d ${srvr} --dport 53 -j LOG --log-level 6 --log-prefix "Legal DNS: " $IPTABLES -A OUTPUT -p udp -i $LAN_IFACE -s ${host} -d ${srvr} --dport 53 -j ACCEPT done done

if [ $MODE = "nat" ] then LIMIT_IP=$HPOT_IP elif [ $MODE = "bridge" ] then LIMIT_IP=$PUBLIC_IP fi

# This will ensure we don't restrict Honeypots talking to eachother, and # we don't log them as outbound connections. If you do not want to see # this log, comment out the logging rule. You will still need the ACCEPT # rule to ensure they honeypots can talk to eachother freely. # $IPTABLES -A OUTPUT -i $LAN_IFACE -s ${host} -d $LAN_IP_RANGE -j LOG --

log-level 6 --log-prefix "Honeypot -> Honeypot: " $IPTABLES -A OUTPUT -i $LAN_IFACE -s ${host} -d $LAN_IP_RANGE -j ACCEPT fi # After all of this hard work...make sure that all of the IPTABLES entries are saved /sbin/iptables-save > /etc/sysconfig/iptables fi

You might also like