Stealthful Sniffing, Intrusion Detection and Logging
In a column about syslog [see “syslog Configuration” in the December 2001 issue of LJ] I mentioned “stealth logging”--by running your central log server without an IP address, you can hide your central log server from intruders. But log servers aren't the only type of system that can benefit from a little stealth. Network sniffers and network intrusion detection systems (NIDSes) probes can also function perfectly well without IP addresses, making them less vulnerable to network attacks than the systems they protect.
This month I demonstrate three ways to use the versatile and powerful Snort—as a stealth sniffer, a stealth NIDS probe and a stealth logger—on a network interface with no IP address. If you're already familiar with Snort, I hope you'll see how easily it can be used stealthfully. If you're new to Snort, this article may be a useful crash course for you. All Snort commands and configurations in this article work equally well on interfaces with and without IP addresses.
Running internet-connected computers is risky. Anytime you provide services, there's a chance that a hostile user might hijack the system through an application vulnerability or simply overwhelm the system with a denial-of-service attack that sends more traffic to your system than it can handle. For web servers, FTP servers and other systems that end users interact with, this risk never can be eliminated—it only can be minimized or contained.
Network probes and log servers are unique, however, because their roles are fundamentally passive; they receive data but don't need to send any. Taking advantage of their passivity by making them inaccessible from the networks they protect makes a lot of sense.
The trade-off is systems without IP addresses must be administered only from the console, or must have another network interface with an IP address. If a system has multiple interfaces, two precautions are vital. First, IP forwarding must be disabled, and second, the interface with an IP address must be connected to a different network from the sniffing/logging interface. It could, for example, be connected to a dedicated “admin” network consisting only of NIDS probes, loggers and administrative workstations.
Physically installing a network interface card (NIC) is easy. Provided that your NIC is supported by your kernel, Linux should automatically detect the NIC and load the appropriate kernel module(s).
However, different distributions handle NIC initialization in different ways. For example, after adding a second NIC to my Red Hat stealth sniffer, I had to create a new file, /etc/sysconfig/network-scripts/ifcfg-eth1, with the following contents:
DEVICE=eth1 USERCTL=no ONBOOT=yes BOOTPROTO= BROADCAST= NETWORK= NETMASK= IPADDR=
Although Red Hat's Kudzu tool automatically detected the new interface, its network-configuration script returned an error when I declined to give an IP address. By creating my own /etc/sysconfig/network-scripts/ifcfg-eth1 file, I got Red Hat to activate the new interface without actually giving it an IP address. On different distributions other steps may be required.
Once you've installed and activated your stealth NIC and connected it to the network you wish to monitor, it's time to try some stealth sniffing. For the remainder of the article I'll assume you've already installed Snort. Most Linux distributions contain their own Snort packages, and the latest version is available at www.snort.org. If you're going to use Snort as a NIDS, it's especially important to be running a recent version of Snort.
The Snort command for “sniffer mode” is simply:
snort -dvi eth1
The -d option tells Snort to decode application data. The -v option tells it to print packets to the console, and the -i option lets you specify the interface to sniff. To tell Snort to skip the hexadecimal data and show only ASCII, use the -C option (Listing 1).
Listing 1. A Packet Dump without Hexadecimal Data
Snort's sniffing functionality works perfectly well on an interface without an IP address.
Intrusion detection is a big topic, and Snort's intrusion detection abilities are diverse and powerful. Before we go any further, then, I want to stress that I'm only scratching the surface: running Snort with a near-default configuration file, using only the included rules, is not the most effective way to use Snort as a NIDS. I'm describing this method here because it's a simple and fast way to get started with NIDS.
To start using Snort in NIDS mode, all you need to do is edit the file /etc/snort/snort.conf and start Snort in dæmon mode. Then, periodically update the Snort rules referenced in snort.conf as new attack signatures become available. Let's briefly discuss each of these steps.
Although you can specify any configuration file you like with Snort's -c startup option, most people use /etc/snort/snort.conf. For the remainder of this article I'll assume that's your choice too. Listing 2 shows a truncated but syntactically complete Snort configuration file.
Listing 2. A Sample snort.conf File
As you can see, a Snort configuration consists of global options, variable declarations, “preprocessor” statements, “output” statements and Snort rules. Global options (“config” statements) provide a handy means of setting most of the options that also can be passed to Snort via startup flags, which saves typing.
Variables are used by Snort rules to make attack detection more accurate. For example, by specifying the IP address of your local name servers via the DNS_SERVERS variable, Snort will disregard certain types of packets sent by your DNS servers that, in other circumstances, might look like attacks.
Preprocessor statements are used to configure preprocessor modules, which are Snort components that act on or alter packets prior to matching them against rules. For example, the preprocessor frag2 re-assembles fragmented packets, and it also watches out for IP-fragment-based attacks and other fragment-related anomalies.
Output statements configure postprocessor modules, which provide different means of logging or otherwise archiving Snort alerts and observed packets. For example, the database postprocessor can be used to log packets to a MySQL database for later correlation and analysis by tools such as ACID (www.andrew.cmu.edu/~rdanyliw/snort/snortacid.html).
Finally, rules can be listed either directly, as with Listing 2's “Cisco Catalyst Remote Access” alert, or in included text files, as with the remainder of Listing 2. The latter method makes it easy to use the rule files maintained by the Snort team at www.snort.org/dl/signatures/snortrules.tar.gz (updated every 30 minutes!) or the ArachNID rules at www.whitehats.com/ids.
To start Snort in NIDS mode using this configuration file, execute this command:
snort -c /etc/snort/snort.conf -D -i eth1
Remember that in earlier examples we set up eth1 as our stealth interface.
By default, Snort will log alerts to /var/log/snort/alert and port-scanning activity to /var/log/snort/portscan.log. Packets referenced in alerts will be logged to subdirectories of /var/log/snort, as described in Listing 3.
A dedicated NIDS probe will need to start Snort in its boot routine. The official Snort RPM automatically installs the startup script /etc/init.d/snortd. Once you've configured Snort to your satisfaction, activate this script for the desired runlevels with the chkconfig command. You may need to write your own startup script if you installed Snort from source.
Running Snort in NIDS mode deserves its own article, even a whole series of articles, but this is enough to illustrate that Snort can be used with a non-IP-addressed interface and to show how to get started with NIDS mode.
Now it's time to combine the previous two techniques in a third one: stealth logging. Normally, a central log server runs syslog or syslog-ng. And indeed, it's possible to capture log packets via a non-IP-addressed interface with Snort and pass them to syslog or syslog-ng. However, it's a lot simpler to let Snort write the packets to a log file itself. The method I'm about to describe uses Snort, tail and awk instead of a traditional logger (on the central logserver, that is; on hosts that send logs you'll still need to configure syslog or syslog-ng as described below).
Suppose you have a LAN segment with several servers whose log messages you'd like sent to a single log server. Suppose further that you're far less concerned with the confidentiality of these log messages than with their integrity. You don't care if anybody eavesdrops the messages, but you don't want the messages tampered with once they've been received by the central log server. Your log server, therefore, is connected to the LAN via a non-IP-addressed interface and will sniff log packets sent to a bogus IP address on the LAN.
On each server from which you wish to send logs, you'll need to do two things. The first step is to configure each sender's system logger to send its messages to the bogus IP. By “bogus”, I only mean that no host actually has that IP address; it must be valid for the LAN in question. Suppose our example LAN's network address is 192.168.1.0/24 and our bogus logger-host address is 192.168.1.111. Servers on the LAN that use standard syslog will each need a line like this in /etc/syslog.conf:
*.info @192.168.1.111
On servers that use syslog-ng, you'll need several lines in /etc/syslog-ng/syslog-ng.conf, like these:
destination d_loghost { udp(ip(192.168.1.111) port(514)); }; filter f_info { level(info); }; log { filter(f_info); destination(d_loghost); };In either case you may wish to specify different criteria from simply saying “all messages whose severity is 'info' or higher”, as shown in the above two examples.
Besides the appropriate lines in its logger's configuration file, each log sender will also need a static ARP entry for the bogus IP address. If your LAN consists of a hub or a series of “cascaded” hubs, this ARP address also can be bogus. If your LAN is switched, you'll instead need to specify the real MAC address (hardware address) of the log server. The command to add a static ARP entry on our example log-sending servers is:
arp -s 192.168.1.111 00:04:C2:56:54:58
where 192.168.1.111 is our bogus log-host IP, and 00:04:C2:56:54:58 is either a bogus MAC address or the real MAC address of our stealth logger's non-IP-addressed interface.
Now each server on our protected LAN is configured to send its logs to 192.168.1.111, and in the case of a switched LAN, they'll be sent to the stealth logger's switch port. Now all we need to do is configure the stealth logger itself.
As with intrusion-detection mode, we can configure Snort as a stealth logger by editing only one file, /etc/snort/snort.conf. Listing 3 shows my Red Hat stealth logger's snort.conf file. Let's dissect it.
Listing 3. /etc/snort/snort.conf/ for a Stealth Logger
First, we have a single variable declaration: EXTERNAL_NET any. None of the other variables we set for NIDS mode are necessary here. Next, we've got a few config statements: dump_payload is equivalent to the command-line option -d; dump_chars_only is equivalent to -C; and logdir specifies the root directory for Snort logs (and is equivalent to -l).
Continuing down Listing 3, we next see one preprocessor statement: we're invoking the frag2 preprocessor with default settings. Large log packets may be fragmented, and if so, frag2 will re-assemble them for us.
Finally, the payoff: a single custom Snort rule. Writing Snort rules is no more complicated than writing iptables or ipchains rules, requiring only a basic understanding of how TCP/IP protocols and applications behave. The “Snort Users' Manual” at www.snort.org/docs/writing_rules documents this clearly and comprehensively. Let's walk through the Snort rule in Listing 3:
log udp 192.168.1.20/32 any -> 192.168.1.111/32 514 (logto: "logged-packets";)
The rule begins with the rule action log. In this case, we're using Snort as a packet logger. So rather than writing a message to /var/log/snort/alert, we want Snort to log any packets that match the rule without writing an alert.
Next comes the rule's matching protocol, udp. syslog messages usually are sent via UDP.
After the rule's protocol comes its source IP, expressed in CIDR notation. 192.168.1.20 is the IP address of the host sending log packets, so we want to match packets sent by that host. /32 is CIDR shorthand for “parse all 32 address bits”, which indicates this is a single host address rather than a range of addresses. To match packets from all hosts on the example LAN, we instead could specify a source IP of 192.168.1.0/24.
The source port follows the source IP, in this case “any” source port. “Any” is a common source-port designator in Snort rules, because with only a few exceptions, TCP/IP client applications send packets from arbitrary, high-numbered ports. In the middle of the rule is its direction operator (->), which signifies that the IP and port to the left of it pertain to the packet's source, and those to the right pertain to its destination. The other allowed direction operator is <>, which indicates that the source and destination IP/port pairs are interchangeable. In other words, Snort should match packets going in either direction between the specified IP addresses on the specified ports.
To the right of the direction operator come the rule's destination IP and destination port designators, 192.168.1.111/32 and 514, respectively. 192.168.1.111 is the bogus IP address to which our servers log, on UDP port 514.
Finally, the rule's options are listed between parentheses, delimited by semicolons if there are multiple options. In this case there's only one, logto: “logged-packets”. The logto option lets us specify a log file to which to write matched packets, in this case /var/log/snort/logged-packets (earlier we set the configuration option logdir to /var/log/snort).
Without the logto: option, Snort will log packets in a new subdirectory of the root log directory, one subdirectory per matched source-IP address. For a stealth logger's purposes, though, it's much better to use the logto: option to specify a single log file to which matched packets for each rule are logged. This allows you to group packets by rule rather than by transaction.
Whew, it took me longer to explain that single rule than it took me to explain the rest of our stealth logger's snort.conf file. But the rule is the important part. If you have additional servers sending log messages, you'll probably want a separate rule for each so their messages are logged to separate files.
Snort is a versatile and powerful tool for sniffing, intrusion detection and packet logging. Configuring it to run stealthily in sniffing mode or NIDS mode is easy; incorporating it into a stealth-logging solution is only slightly less so. Good luck with your logging and NIDS endeavors, stealthful or not!
Mick Bauer (mick@visi.com) is a network security consultant for Upstream Solutions, Inc., based in Minneapolis, Minnesota. He is the author of the upcoming O'Reilly book Building Secure Servers With Linux, composer of the “Network Engineering Polka” and a proud parent (of children).