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.
|