Cover V13, i04
apr2004.tar

Content Filtering and Inspection with fwsnort and psad

Michael Rash

Network intrusion detection systems deployed on IP networks must be able to inspect packet contents and all fields of packet headers for telltale characteristics that may indicate nefarious activity. The libpcap library provides a programming interface that facilitates packet inspection, and many network intrusion detection systems and sniffers (e.g., Snort, bro, tcpdump, and dsniff) make use of libpcap. Netfilter in the Linux kernel generates sufficiently detailed logs from an intrusion detection standpoint without libpcap, and coupled with the string match extension can even search and generate logs for signatures in the application portion of IP packets.

In this article, I'll present two programs -- fwsnort and psad -- that together can detect and send alerts for more than 75% of the ~1800 rules in version 2.0 of the Snort intrusion detection system (http://www.snort.org) through the exclusive use of netfilter logs and extensions (http://www.netfilter.org). Both fwsnort and psad (which stands for Port Scan Attack Detector) are free software released under the GPL, and can be downloaded from:

http://www.cipherdyne.org/
The goal of fwsnort and psad is to see how far iptables can go towards acting as an intrusion detection system (IDS). Note that although fwsnort and psad together can detect many Snort rules, standard IDS evasion techniques such as packet fragmentation, session splicing, polymorphic shellcode, and string manipulation will defeat the iptables string matching function. Thus, such trickery will also defeat fwsnort and psad for application layer attacks. These programs are not meant to function as a full-blown intrusion detection system. They are meant to supplement an existing IDS by providing analysis of, and alerting for, iptables log messages.

Iptables Logging

Iptables has the capability of logging nearly every field of the network and transport headers. However, not all fields are logged by default because some fields can only be logged through the use of command-line options to iptables commands. Such fields include IP options, TCP options, and TCP sequence numbers, which can be logged via the --log-ip-options, --log-tcp-options, and --log-tcp-sequence arguments, respectively. To illustrate the default logging capabilities of iptables, below are displayed three example log messages that were generated by a TCP syn packet, a UDP packet, and an ICMP echo request. All three packets were logged by the iptables FORWARD chain running on a Linux 2.4.22 kernel:

TCP syn:

Dec 07 10:27:11 orthanc kernel: DROP IN=eth2 OUT=eth0 SRC=192.168.20.25
DST=204.174.xxx.xxx LEN=60 TOS=0x10 PREC=0x00 TTL=63 ID=56341 DF PROTO=TCP
SPT=37481 DPT=6776 WINDOW=5840 RES=0x00 SYN URGP=0
UDP:

Dec 07 10:31:13 orthanc kernel: DROP IN=eth2 OUT=eth0 SRC=192.168.20.25
DST=204.174.xxx.xxx LEN=28 TOS=0x00 PREC=0x00 TTL=63 ID=26893 PROTO=UDP
SPT=46564 DPT=20433 LEN=8
ICMP:

Dec 07 10:33:17 orthanc kernel: DROP IN=eth2 OUT=eth0 SRC=192.168.20.25
DST=204.174.xxx.xxx LEN=84 TOS=0x00 PREC=0x00 TTL=63 ID=0 DF PROTO=ICMP TYPE=8
CODE=0 ID=34653 SEQ=0
There are several common fields in the three packets above, as follows:

  • The "DROP" string -- because the iptables rule that generated the log message in each case made use of the -- log-prefix option.
  • The IN and OUT interfaces on the underlying Linux system (the OUT interface is blank if packets are logged by the INPUT chain).
  • Source and destination IP addresses.
  • Several other fields of the IP header including the length, tos "type" and "precedence", ttl, ip id, fragment bits, and the protocol.
  • Both TCP and UDP log messages include the source and destination ports.

Fields not common to, among the three packets above, include:

  • The TCP window size, reserved bits, TCP flags, and the urgent pointer.
  • The UDP length.
  • The ICMP type, code, id, and sequence number.

A complete summary of iptables logging options can be found in the "Netfilter Log Format" by Manfred Bartz (see References).

So far, we have seen iptables log messages that include information about the network and transport headers, but what about the application layer? More than 90% of all Snort rules use the "content", "uricontent", or "content-list" field definitions, so logging application layer data is essential to detecting most Snort rules.

The iptables string match extension allows iptables to search for strings in the application portion of IP packets and apply any of the standard targets to packets that contain matching strings. Specifically, the ACCEPT, LOG, DROP, REJECT, QUEUE, or RETURN targets can determine the fate of the packet as it traverses one (or more) interfaces on the firewall. As with all iptables extensions, there are two main components: a kernel module (may be compiled in), and the corresponding userspace code that gets compiled into a library that is used by the iptables binary. The kernel portion of the string match extension is responsible for performing a Boyer-Moore search (very fast) against the data portion of IP packets. The userspace code takes the string from the command line and adds it to the iptables kernel data structures in a running Linux kernel.

The following example illustrates the iptables command necessary to have iptables detect and log a Web application attack rule (in Snort parlance, signatures are called "rules") from the Snort IDS:

snort sid:1332, "WEB-ATTACKS /usr/bin/id command attempt":

# iptables -I FORWARD 1 -p tcp --dport 80 -m string --string "/usr/bin/id" -j
LOG --log-prefix "SID1332 "
Resulting log message:

Apr 23 10:20:08 orthanc kernel: SID1332 IN=eth2 OUT=eth0 SRC=192.168.20.25
DST=204.174.xxx.xxx LEN=65 TOS=0x10 PREC=0x00 TTL=63 ID=61688 DF PROTO=TCP
SPT=34380 DPT=80 WINDOW=5840 RES=0x00 ACK PSH URGP=0
Fwsnort

Fwsnort translates Snort rules into equivalent iptables rules and builds a Bourne shell script to implement the resulting iptables policy. Fwsnort is based on the original "snort2iptables" shell script written by William Stearns (see References). In addition to being written in Perl, fwsnort adds two significant features: a custom patch to the userspace code of iptables itself, which adds a "--hex-string" option, and the ability to parse an existing iptables ruleset with the IPTables::Parse Perl module to determine which Snort rules could potentially be allowed through the policy. Also, by using the "--snort-sid" option, fwsnort can translate a single Snort rule into an equivalent iptables rule. This option is useful for determining whether an iptables policy will accept traffic matching any particular Snort rule.

Snort-2.0 contains more than 1800 rules. Although iptables can handle several thousand rules, it is wasteful to include rules for traffic that the firewall will disallow in the first place. As an example, suppose there is a Web server on an internal network protected by an iptables firewall, and suppose further that iptables has been configured not to allow any external access to the Web server over port 80 since it is meant for internal use only. In this situation, it would be pointless to translate the Snort rules for Web attacks into iptables detection rules. After all, iptables should be configured to allow traffic into/through the firewall that is only strictly necessary for the network to function as desired and all other traffic should be logged and dropped.

Iptables "--hex-string" Patch

Content fields in Snort rules frequently contain data specified with hexadecimal codes that have no ascii-printable equivalent. Without the patch provided by fwsnort, the only way for iptables to search for such data is to translate the hex characters in Snort into their ascii equivalent, and the result is most likely a rule containing a non-printable string. The --hex-string patch has been accepted by the iptables maintainers and is included within iptables as of the 1.2.9 release. If you are running an older version of iptables, the --hex-string patch is included with the fwsnort sources so it can easily be added by recompiling the user portion of iptables. The next two examples illustrate the usage of the --hex-string option.

Example 1

Snort sid 663 in smtp.rules contains the following content field:

"|7c 73 65 64 20 2d 65 20 27 31 2c 2f 5e 24 2f 27|"
Using the --hex-string patch, we can write an equivalent iptables rule (source and destination networks removed for brevity):

iptables -I FORWARD 1 -p tcp --dport 25 -m string \
  --hex-string "|7c 73 65 64 20 2d 65 20 27 31 2c 2f 5e 24 2f 27|" \
  -j LOG --log-prefix "SID663 "
Example 2

The --hex-string patch also accepts multiple hex data fields delimited by the "|" character; thus, content fields in Snort rules can be input directly into iptables rules without modification. For example, in the "backdoor.rules" file, sid 105 for the Dagger backdoor has the following content field:

|3200000006000000|Drives|2400|
The equivalent iptables rule (source and destination networks again removed for brevity) follows:

iptables -I FORWARD 1 -p tcp --sport 2589 --dport 1024:65535 -m string
--hex-string "|3200000006000000|Drives|2400|" -j LOG --log-prefix "SID105 "
Translation Options and Stats

Although the iptables logging format is fairly complete and gives a substantial amount of information about packet headers, not all Snort detection keywords can be mapped into an equivalent iptables filter or log field. Several Snort fields such as "id" and "seq" are logged by iptables, but there is no way to filter packets on them directly. With the exception of the "nocase", "offset", and "depth" keywords, fwsnort only generates signatures for those Snort rules that contain detection keywords that iptables can be instructed to filter. (Fwsnort can be executed with --strict to make it not translate rules that contain the "nocase", "offset", or "depth" fields).

Armed with the above information, how many Snort rules can be faithfully translated into iptables rules? Fwsnort answers this question for us (see Figure 1). From the output in Figure 1, we see that fwsnort was able to translate 1415 of 1823 Snort rules, or about 78%. We also see that for the Linux system on which fwsnort was executed, only 61 of these rules are applicable to the current iptables configuration, and most of these rules are ICMP related.

fwsnort.sh

Fwsnort generates a Bourne shell script (/etc/fwsnort/fwsnort.sh) that contains all the iptables commands necessary to implement an iptables policy that is based on as many applicable Snort rules as possible. By default, the iptables commands just log traffic matching Snort rules, but fwsnort can also build a policy that instructs iptables to reject such traffic at the same time. The relevant command-line options are --ipt-reject and --ipt-no-log. If --ipt-reject is used, then the REJECT target will generate an ICMP port unreachable message in response to matching packets.

This presents no difficulty for UDP and ICMP packets because these protocols are connectionless and, thus, rejected packets will not cause retransmissions. However, such a simplistic solution does not work as well for TCP where every packet of an established session is acknowledged and missing packets in the stream are retransmitted. For TCP packets, fwsnort uses the --reject-with tcp-reset iptables option so that if, for example, a packet containing a buffer overflow string for an internal Web server is sent across the firewall interfaces, then the entire session will be taken down by the firewall before the attack ever reaches the internal Web server.

Depending upon the number of interfaces on the firewall, fwsnort creates and adds iptables rules to as many as five user-defined chains. Fwsnort can handle up to three interfaces: one external, one internal, and a DMZ interface. The only required interface is the external one because iptables may be deployed on a single-homed Linux host. Figure 2 contains an excerpt from an example fwsnort.sh script generated by fwsnort. This illustrates several iptables commands used to build a policy for detecting Snort rules from the Snort backdoor.rules file. Note that the comments preceding each rule contain the original Snort message and classtype (we only want to include the SID in the --log-prefix to conserve kernel memory).

psad

Now that we have seen iptables log messages generated from application layer data, what about triggering alerts from such messages? For that we turn to psad. Psad is a collection of three system daemons (psad, kmsgsd, and psadwatchd) that analyze iptables log messages for port scans, probes for backdoor programs, and SID<nnn> strings such as those generated by fwsnort. Psad began as part of the Bastille Linux project when it was decided that Bastille should offer the capability of analyzing iptables log messages.

Psad eventually became its own open source project and has an active development cycle with a new release once every two months on average. Psad features verbose email alerts that include the source, destination, scanned port range, begin and end times, TCP flags and corresponding nmap options, Snort rule messages for matched SIDs, auto-blocking of offending IP addresses via dynamic reconfiguration of iptables rulesets (disabled by default), DShield alerts, and more. Note, however, that automatically blocking traffic from an IP is not generally a good idea because the attacker will likely quickly discover this and then spoof scans from all of your favorite Web sites.

As iptables log messages are generated, psad uses a scoring mechanism to assign a danger level to scans. This level is based on the number of packets logged by iptables, the range of ports scanned, and whether the scan matches any TCP, UDP, or ICMP signatures that are automatically associated with a specific danger level. By making use of the complete logging of TCP flags in iptables messages, psad can detect TCP connect(), SYN (half-open), FIN, NULL, XMAS, SYN/FIN, nmap, and OS fingerprinting scans. Because port scans don't involve any application layer data, psad can detect all such scans without fwsnort.

Psad Architecture

During installation, psad reconfigures syslogd to write all kern.info messages to a named pipe located at /var/lib/psad/psadfifo. Kmsgsd is responsible for opening the pipe, reading any iptables messages from it that match a (configurable) log prefix string of "DROP", and writing all such messages to the psad data file /var/log/psad/fwdata where they will be analyzed by psad. In this way, psad is supplied with a stream of data that contains only messages that iptables has generated as a result of packets deemed unfit to pass through (or at least logged by) the security policy. Recall that logging rules are independent of DROP rules in iptables. Lastly, psadwatchd is a software watchdog that is responsible for restarting psad or kmsgsd should either daemon die for any reason.

Psad Log Directories

Psad employs the same logging strategy that Snort uses and logs various pieces of information about a scan or other detected signatures in /var/log/psad/<ip>, where <ip> is the scanning source IP address. This allows psad to easily display summary information by querying the filesystem, and allows the administrator to view all IP addresses that have scanned the system by issuing a quick ls /var/log/psad/.

Sample psad Alerts

The psad alerts (shown in Figure 3) were generated for a FIN scan (which does not require fwsnort), a /usr/bin/id attempt against a Web server (snort sid: 1332), and a DNS exploit (sid: 265) against a DNS server. Note that the whois information normally included in psad email alerts has been removed for brevity.

psad --Status Option

Psad provides the --Status command-line argument to display a summary of all IP addresses that have directly scanned the network or the firewall. The output includes system load information for all three psad daemons, the total number of iptables message processed, and a table that lists scanning source IP addresses along with TCP, UDP, and ICMP packet counts, and the iptables chain and physical interface on which the scan was detected. A sample psad --Status output appears in Figure 4.

Conclusion

This article has explored network intrusion detection as it relates to netfilter logs. The relatively complete logging capabilities of netfilter make it a good candidate to supplement existing intrusion detection systems. Also, through judicious application of various options, iptables can be used to detect many of the signature rules included in Snort, including those that inspect the application portion of IP packets. Two pieces of open source software -- fwsnort and psad -- have been developed to automate the process of getting the most out of netfilter logs.

References

Netfilter Log Format by Manfred Bartz -- http://logi.cc/linux/netfilter-log-format.php3

snort2iptables -- http://www.stearns.org/snort2iptables/

Bastille Linux -- http://www.bastille-linux.org

Michael Rash holds a Master's Degree in Applied Mathematics from the University of Maryland, and writes software for a networking company in Columbia, Maryland. He spends most of his free time working on security software for Linux and enjoys playing the violin for the county orchestra. He can be contacted at: mbr@cipherdyne.org.