One of the most important features for any IDS is the ability to search application layer data for telltale sequences of malicious bytes. However, because the structure of applications is generally much less strictly defined than that of network or transport layer protocols, intrusion detection systems must be flexible when it comes to inspecting application layer data.
For example, when inspecting application layer communications, if an IDS assumes that certain sequences of bytes are inviolate (and may therefore be ignored), then changes in the application layer protocol might invalidate this assumption and cause the IDS to miss attacks that are delivered in unexpected ways. A vulnerability in a particular implementation of such an application layer protocol might be exploitable by manipulating the sections within the protocol that the IDS skips.
We therefore need a flexible mechanism for inspecting application layer data. The ability to perform string matching against the entire application payload in network traffic is a good first step and is provided by the iptables string match extension.
NOTE This is the reason why I emphasized enabling string match support in “Kernel Configuration” on page 14. String matching will also be leveraged heavily in Chapters 9, 10, and 11, when we discuss fwsnort.
The iptables string match extension allows packet payload data to be searched for matching strings using the fast Boyer-Moore string search
algorithm (see http://www.cs.utexas.edu/users/moore/best-ideas/stringsearching).
This algorithm is commonly used by intrusion detection systems, including the champion open source IDS Snort (http://www.snort.org), because of its ability to quickly match strings within payload data.
NOTE String matching has been available in iptables since the 2.4 kernels, but an architectural change with respect to how packet data structures were stored within kernel memory (sk_buff structures were allowed to span non-contiguous memory) broke the string matching feature in kernels 2.6.0 through 2.6.13.5. The string match
extension was rewritten for the 2.6.14 kernel, and it has been included within the kernel ever since.
7.7.1.1 Observing the String Match Extension in Action
In order to test the iptables string matching feature, we construct a simple iptables rule that uses the string match extension to verify that it functions as advertised. The following rule uses the iptables LOG target to generate a syslog message when the string "tester" is sent to a Netcat server that is listening on TCP port 5001. (We need the ACCEPT rule so that the default iptables policy from Chapter 1 will allow the establishment of the TCP connection from an
external source.)
[iptablesfw]# iptables -I INPUT 1 -p tcp --dport 5001 -m string --string "tester"
--algo
� bm -m state --state ESTABLISHED� -j LOG --log-prefix
"tester" [iptablesfw]# iptables -I INPUT 2 -p tcp --dport 5001 -j ACCEPT
Notice at �above the --algo bm command-line argument to iptables. The string match extension is built on top of a text-searching infrastructure in the Linux kernel (located within the linux/lib directory in the kernel sources).
It supports several different algorithms, including the Boyer-Moore string search algorithm (the bm above), and the Knuth-Morris-Pratt string- searching algorithm (kmp).1
The -m state --state ESTABLISHED command-line arguments at � restrict
the string match operation to packets that are part of established TCP connections, and this means that someone cannot cause the iptables rule to match
on a spoofed packet from an arbitrary source address—a bidirectional connection must be established.
We’ll use Netcat to spawn a TCP server that listens locally on TCP
port 5001, and then we’ll use it again from the ext_scanner system as a client to send the string "tester" to the server:
[iptablesfw]$ nc -l -p 5001
[ext_scanner]$ echo "tester" | nc 71.157.X.X 5001
Now we’ll examine the system logfile for evidence that the string match rule generated the appropriate syslog message:
[iptablesfw]# tail /var/log/messages | grep tester Jul 11 04:19:14 iptablesfw kernel: tester IN=eth0 OUT=
MAC=00:13:d3:38:b6:e4:00:30:48:80:4e:37:08:00 SRC=144.202.X.X DST=71.157.X.X LEN=59 TOS=0x00 PREC=0x00 TTL=64 ID=41843 DF PROTO=TCP SPT=55363 DPT=5001 WINDOW=92 RES=0x00 ACK PSH URGP=0
Notice the log prefix tester in bold above. By examining the remaining portion of the log message, we can confirm that the associated packet was sent from the ext_scanner system to our Netcat server listening on TCP port 5001.
NOTE We could have achieved the same result as above by using telnet (running in line mode) as our client instead of Netcat, so that the entire string "tester" is contained within a single packet. This works well enough, but telnet has some serious limitations: It is unable to interact with UDP servers, and it is also difficult to use telnet to generate arbitrary
non-printable characters.
7.7.1.2 Matching Non-Printable Application Layer Data
When running as a client, Netcat can interact with UDP servers just as easily as it can with those that listen on TCP sockets. When combined with a little
Perl, Netcat can send arbitrary bytes across the wire, including ones that cannot be represented as printable ASCII characters. This feature is important because
many exploits utilize non-printable bytes that cannot be represented by printable ASCII characters; in order to simulate such exploits as they are sent across the wire, we need the ability to generate the same bytes from our client.
For example, suppose that you need to send a string of 10 characters that represent the Japanese yen to a UDP server listening on port 5002, and that you want iptables to match on these characters. According to the ISO 8859-9 character set (type man iso_8859-9 at a command prompt), the hex code A7
represents the yen sign, and so the commands below will do the trick.
We first execute iptables with the --hex-string argument to iptables, along with the bytes specified in hex between | characters like so:
[iptablesfw]# iptables -I INPUT 1 -p udp --dport 5002 -m string --hex-string
"|a7a7a7a7a7a7a7a7a7a7|" --algo bm -j LOG --log-prefix "YEN "
Next, we spawn a UDP server on port 5002.2 Finally, we use a Perl
command to generate a series of 10 hex A7 bytes, and we pipe that output through Netcat to send it over the network to the UDP server: [iptablesfw]
$ nc -u -l -p 5002
[ext_scanner]$ perl -e 'print "\xa7"x10' | nc -u 71.157.X.X 5002
Sure enough, iptables matches the traffic, as you can see by the syslog log message (note the YEN log prefix shown in bold):
[iptablesfw]# tail /var/log/messages | grep YEN Jul 11 04:15:14 iptablesfw kernel: YEN IN=eth0 OUT=
MAC=00:13:d3:38:b6:e4:00:30:48:80:4e:37:08:00 SRC=144.202.X.X DST=71.157.X.X
LEN=38 TOS=0x00 PREC=0x00 TTL=64 ID=37798 DF PROTO=UDP SPT=47731 DPT=5002 LEN=18