11.2 Using TripwireAmong the most celebrated and useful things to come out of Purdue's COAST project (http://www.cerias.purdue.edu/coast/) was the Unix integrity checker Tripwire, created by Dr. Eugene Spafford and Gene Kim. Tripwire was originally both open source and free, but in 1997, Tripwire went commercial, and fee-free use was restricted to academic and other noncommercial settings. Happily, a couple of years ago, Tripwire, Inc. released "Tripwire Open Source, Linux Edition." Until Tripwire Open Source was released, the older Academic Source Release (ASR) lacked features long available in commercial versions of Tripwire. But Tripwire Open Source is a more-or-less current version of the commercial product. Although it still lacks a few "enterprise" features such as centralized management of multiple systems (Tripwire, Inc. understandably still wishes to differentiate its commercial product line), it is functionally very similar to the commercial Tripwire for Servers. Note that Tripwire Open Source is free for use only on noncommercial Unices (i.e., Linux and Free/Net/OpenBSD). In fact, it's officially supported only on Red Hat Linux and FreeBSD, although there's no obvious reason why it shouldn't compile and run equally well on other Linux and BSD distributions. (I run it not only on Red Hat, but also on SuSE and Debian Linux, with no problems to report). For commercial Unices such as Sun Solaris and HP-UX, commercial Tripwire is still the only legal option in commercial settings. 11.2.1 Obtaining, Compiling, and Installing TripwireAs of this writing, the most current version of Tripwire Open Source is 2.3.1-2. If your Linux distribution of choice doesn't provide a reasonably current Tripwire package (Debian 2.2 and SuSE 7.3, for example, both ship with Tripwire 1.2, the 1994 Academic Source Release!), then I strongly recommend that you obtain, compile, and install the latest version. Needlessly running old security software is seldom a good idea; furthermore, as Linux users, we're eligible to use Tripwire Open Source. Tripwire Open Source can be downloaded as a source-code tarball at http://sourceforge.net/projects/tripwire/. To compile Tripwire Open Source, move the archive to /usr/src and untar it, e.g.: tar -xzvf ./tripwire-2.3.1-2.tar.gz. Next, check whether you have a symbolic link from /usr/bin/gmake to /usr/bin/make. (Non-Linux Unices don't all come with GNU make, so Tripwire explicitly looks for gmake — but on most Linux systems, this is simply called make). If you don't have such a link, create one. Another thing to check for is a full set of subdirectories in /usr/share/man — Tripwire will need to place manpages in man4, man5, and man8. On my Debian system, /usr/man/man4 was missing; as a result, the installer created a file called /usr/man/man4, which of course was actually a manpage that was incorrectly copied to that name rather than within it. Now change your working directory to Tripwire source's root directory — e.g., /usr/src/tripwire-2.3.1-2 — and read the files README and INSTALL. They're both brief but important. Finally, change to the source tree's src directory (e.g., /usr/src/tripwire-2.3.1-2/src), and make any necessary changes to the variable definitions in src/Makefile. Be sure to verify that the appropriate SYSPRE definition is uncommented (SYSPRE = i686-pc-linux, or SYSPRE = sparc-linux, etc.). Now you're ready to compile. While still in Tripwire's src directory, enter this command: make release The build will take a while, so now is a good time to grab a sandwich. When it's done (Tripwire, not the sandwich), navigate up one directory level (e.g., to /usr/src/tripwire-2.3.1-2) and execute these two commands: cp ./install/install.cfg . cp ./install/install.sh . Now open install.cfg with your favorite text editor to fine tune the variables within: while the default paths are probably fine, you should at the very least examine the Mail Options section. This is where we initially tell Tripwire how to route its logs (I say "initially" because these settings can be changed later). If you set TWMAILMETHOD=SENDMAIL and specify a value for TWMAILPROGRAM, Tripwire will use the specified local mailer (sendmail by default) to deliver its reports to a local user or group. If instead you set TWMAILMETHOD=SMTP and specify values for TWSMTPHOST and TWSMTPPORT, Tripwire will mail its reports to an external email address via the specified SMTP server and port. If you or other system administrators routinely log on to and read email on the system on which you're installing Tripwire, then the SENDMAIL method is probably preferable. But if you typically administer this host remotely from other systems, the SMTP method is probably better. Again, if you change your mind later, these settings can be changed in Tripwire's configuration file at any time. Once install.cfg is set to your liking, it's time to install Tripwire. While still in the root directory of the Tripwire source distribution, enter the following: sh ./install.sh You will be prompted for site and local passwords: the site password protects Tripwire's configuration and policy files, whereas the local password protects Tripwire's databases and reports. This allows the use of a single policy across multiple hosts in such a way as to centralize control of Tripwire policies but distribute responsibility for database management and report generation. If you do not plan to use Tripwire across multiple hosts with shared policies, there's nothing wrong with setting the site and local Tripwire passwords on a given system to the same string. In either case, choose a strong passphrase that contains some combination of upper-and lowercase letters, punctuation (which can include whitespace), and numerals.
11.2.2 Configuring TripwireJustly or not, Tripwire has a reputation of being unintuitive to configure. In my opinion, the configuration syntax in Tripwire Version 2 is much simpler than Version 1's (which is yet another reason to run Tripwire Open Source rather than ASR!). Regardless, I think you'll find the time you spend reading the next section and fine-tuning Tripwire on your own systems to be well worth the effort. Let's examine the tasks that comprise Tripwire configuration and usage, one at a time. 11.2.2.1 Managing the configuration fileWhen you install Tripwire (whether via binary package or source build), a default configuration file is created, /etc/tripwire/tw.cfg. You can't edit this file because it's an encrypted binary, but for your convenience, a clear-text version of it, called twcfg.txt, should also reside in /etc/tripwire. This is the file to change if you've had second thoughts about any of the settings you gave the installation script when you installed Tripwire. Example 11-1 lists a sample (clear-text) Tripwire configuration. Example 11-1. Sample Tripwire configurationROOT =/usr/sbin POLFILE =/etc/tripwire/tw.pol DBFILE =/var/lib/tripwire/$(HOSTNAME).twd REPORTFILE =/var/lib/tripwire/report/$(HOSTNAME)-$(DATE).twr SITEKEYFILE =/etc/tripwire/site.key LOCALKEYFILE =/etc/tripwire/squeezebox-local.key EDITOR =/bin/vi LATEPROMPTING =false LOOSEDIRECTORYCHECKING =false MAILNOVIOLATIONS =true EMAILREPORTLEVEL =3 REPORTLEVEL =3 MAILMETHOD =SMTP SYSLOGREPORTING =false SMTPHOST =mail.polkatistas.org SMTPPORT =25 Many of the settings shown in Example 11-1 are self-explanatory; others are things you already considered when you installed Tripwire. Specifically, MAILMETHOD corresponds to the Tripwire postinstallation script's variable TWMAILMETHOD, MAILPROGRAM corresponds to TWMAILPROGRAM, SMTPHOST to TWSMTPHOST, and SMTPPORT to TWSMTPPORT. It's unlikely that you'll need to change these settings very often, if at all, but if you do, a complete reference is available in the twconfig(4) manpage. One setting you should strongly consider customizing is DBFILE. As I mentioned earlier in the chapter, an integrity checker should ideally refer to a database stored on read-only media. For example, if you create a directory called /mnt/twdb and specify /mnt/twdb/myhostname.db as the value of DBFILE in your Tripwire configuration (substituting myhostname.db with your host's name), Tripwire will write its configuration to this directory when you initialize it. You can then burn this file to a CD-ROM, erase it from /mnt/twdb, and mount the database CDROM on /mnt/twdb. I should point out one more setting, one brought to my attention by Tripwire Open Source Project Manager, Ron Forrester: MAILNOVIOLATIONS. If this is set to false, then Tripwire will email its reports only when violations are found. But setting it to true causes a report to be emailed each time a Tripwire check is run, even if there are no violations. This provides a "heartbeat" function that makes it obvious if an intruder suppresses Tripwire activity. Any time you edit the clear-text version of your Tripwire configuration, re-encrypt it with the command: twadmin --create-cfgfile --site-keyfile ./site.key twcfg.txt where site.key is the name of the site key created at installation time and twcft.txt is the name of the clear-text configuration file you just edited and wish to encrypt; you can name them whatever you like. Don't forget to specify the site-keyfile, or twadmin will return an error.
11.2.2.2 Editing or creating a policyTripwire's policy file is its brain: it specifies what to look at, what to look for, and what to do about it. It's also a little on the user-hostile side, though not nearly so bad in this regard as, say, sendmail.cf (but prepare to memorize some abbreviations!). Tripwire Open Source comes with a default policy file, and you may, if you like, use this as your own personal Tripwire policy. But since the default policy was created for a Red Hat system running nearly everything in the distribution, you should probably edit this policy rather than use it as is. If your policy doesn't check enough files or doesn't look closely enough at the ones it does check, Tripwire's purpose is defeated: shenanigans will go undetected. Conversely, if the policy looks too closely at files that you expect to change, Tripwire will generate false positives; too many of these may distract your attention from actual discrepancies. But, to repeat my admonition from the beginning of the chapter, some false positives are acceptable; no false negatives are! Err, therefore, on the sake of "noisiness" rather than convenience. You'll almost certainly need to adjust your policy on an ongoing basis and especially after the first time you run an integrity check. Thus, even if you do have a Red Hat system with exactly the same configuration as that for which the default Tripwire Open Source policy was designed, you still need to learn proper Tripwire policy syntax. 11.2.2.3 Policy file structure and syntaxI'm going to explain policy file structure and syntax by dissecting a working policy file piece by piece. The first piece is from the very beginning of a sample policy file (Example 11-2). Example 11-2. Some variable definitionsWEBROOT=/home/mick/www; CGIBINS=/home/mick/www/cgi-bin; TWPOL="/etc/tripwire"; TWDB="/var/lib/tripwire"; As you can see, this first piece of policy shows some variable definitions. All of the variables in Example 11-2 are policy-specific variables; none of them hold intrinsic meaning to Tripwire binaries. They're here to save typing later on in the policy. Example 11-3 lists the next piece of our sample policy. Example 11-3. Fancier variable definitionsBINS = $(ReadOnly) ; # Binaries that should not change DIR_SEMISTATIC = +tpug ; # Dir.s that shouldn't change perms/ownership SIG_MED = 66 ; # Important but not system-critical files Like the variables in Example 11-2, these are policy-specific variables. But as you can see, they create more typing, not less: these have been declared to attach meaningful labels to abstract values. The first line shows us how to set one variable to the value of another. This is very similar to BASH-shell syntax, but note the parentheses around the second variable's name. Both lines one and two in Example 11-3 define property masks . Property masks are abbreviations of the file properties Tripwire examines. Since property mask strings can be cryptic and unwieldy, most people prefer to use variables to refer to them. In fact, Tripwire comes with a number of predeclared variables set to common property masks. The first line of this listing actually refers to one of these, ReadOnly, which is a property mask for files that shouldn't change in any way (e.g., binaries). We'll discuss property masks shortly. The third line of Example 11-3 creates a name for a severity level. Severity levels can be used to differentiate between rules of various importance. When the tripwire command is invoked with the --severity N parameter, only rules that have been assigned severity levels equal to or greater than N will be run. In Tripwire's default twpol.txt file, three example severity levels are helpfully defined. If this parameter is not used, all rules will be run. But note that if a rule has no severity level associated with it, its severity will be zero by default (i.e., that rule will only be run when the --severity parameter isn't specified). Now that we've got a feel for policy variables and what they're used for, let's look at some actual rules (Example 11-4). Example 11-4. A group of rules# Mick's Web Junk ( rulename = "MickWeb", severity = $(SIG_MED), emailto = [email protected] ) { $(WEBROOT) -> $(ReadOnly) (recurse=1) ; !$(WEBROOT)/guestbook.html ; $(CGIBINS) -> $(BINS) ; /var/log/httpd -> $(Growing) ; /home/mick -> $(DIR_SEMISTATIC) (recurse=0) } Rules may either stand alone or be grouped together based on common attributes; Example 11-4 shows a group of rules (contained within "curly brackets") preceded by several shared attributes (in parentheses). This group's rulename is "MickWeb," the group's severity is 66 (see Example 11-3), and reports involving this group will be emailed to [email protected]. Note that attributes are comma delimited, and rules are semicolon delimited. Attributes can also be assigned both to rule groups and to individual rules: the first rule in Example 11-4 has the attribute recurse set to 1, which means that the directory /home/mick/www will be checked down one level (i.e., the directory itself plus everything immediately below, but no further). By default, directories are recursed as far down as they go; in effect, the recurse attribute has a default value of True. Attributes assigned to single rules usually override those assigned to rule groups. The exception is the attribute emailto, which is cumulative: if a group has a shared emailto string and one of that group's rules has a different emailto string, reports relevant to that rule will be emailed to both email addresses. There are only four different attributes: rulename, severity, emailto, and recurse. For more detailed information, see the documentation cited in Section 11.5 at the end of this chapter. After the group attributes for MickWeb, we have some actual rules (lines 8 through 11). Note the use of variables to specify both objects (the Tripwire term for files and directories) and property masks. In fact, none of the rules in Example 11-4 uses a longhand property mask! This is common practice, as it makes the policy more readable. The first rule in Example 11-4: $(WEBROOT) -> $(ReadOnly) (recurse=1) ; tells Tripwire to treat the first level of my WWW directory as read-only. Next, we have a statement beginning with an exclamation point: !$(WEBROOT)/guestbook.html ; Such a statement is called a stop point: it defines an exception to a rule. In this case, the stop point tells Tripwire to ignore changes to the file /home/mick/www/guestbook.html. Attributes do not apply to (nor may they be assigned to) stop points. Examples 11-2 through 11-4 constitute a semantically complete policy file, but not a useful one — it doesn't check any system binaries or configuration files at all. Real policies are much longer. Here's the policy in one listing (Example 11-5). Example 11-5. A sample policy fileWEBROOT=/home/mick/www; CGIBINS=/home/mick/www/cgi-bin; TWPOL="/etc/tripwire"; TWDB="/var/lib/tripwire"; BINS = $(ReadOnly) ; # Binaries that should not change DIR_SEMISTATIC = +tpug ; # Directories that shouldn't change perms/ownership SIG_MED = 66 ; # Important but not system-critical files # Mick's Web Junk ( rulename = "MickWeb", severity = $(SIG_MED), emailto = [email protected] ) { $(TWPOL) -> $(Readonly) ; $(WEBROOT) -> $(ReadOnly) (recurse=1) ; !$(WEBROOT)/guestbook.html ; $(CGIBINS) -> $(BINS) ; /var/log/httpd -> $(Growing) ; /home/mick -> $(DIR_SEMISTATIC) (recurse=0) } You may have noticed that this entire file contains only one explicit reference to a property mask: the variable declaration in which DIR_SEMISTATIC is set to +tpug. What does that mean? 11.2.2.4 Property masksA property mask is a series of file or directory properties that should be checked or ignored for a given object. Properties following a + are checked; those following a - are ignored. The properties are abbreviated as follows (Table 11-1).[1]
Tripwire's own documentation describes these properties in depth. If you're unfamiliar with some of the more arcane file attributes (e.g., "inode reference count"), I recommend the paper "Design and Implementation of the Second Extended Filesystem" by Card, Ts'o, and Tweedie (see Section 11.5 at the end of this chapter). As for hash types, note that you generally won't want to use more than one or two cryptographic hashes per rule: these are CPU intensive. On the other hand, do not rely solely on CRC-32 hashes, which are fast but much easier to subvert. Remember, Tripwire doesn't compare file attributes directly: it compares hashes. So give this matter some thought and choose your hash types carefully. As I mentioned earlier, Tripwire has a number of predefined (hardcoded) variables that describe common property masks (Table 11-2).
In most cases, it's much simpler to use the predefined property masks than to "roll your own" masks. If you need a property mask that's only slightly different than a predefined mask, you can still use it: simply combine it with additional properties, e.g.: /dev/console -> $(Dynamic)-u ; # Dynamic, but UID can change which is the same as: /dev/console -> +pingutd-srlbamcCMSH-u ; # Dynamic, but UID can change Note that in the longhand example, the +....u near the beginning of the mask is canceled out by the -u at the very end. This works, but it is notated that way here only to illustrate the literal translation of $(Dynamic)-u. 11.2.2.5 Installing the policy fileAfter you've created what seems like a reasonable policy, you need to install it. The command to encrypt, sign, and install a system's first Tripwire policy is as follows: twadmin --create-polfile policyfile.txt Use this command only for your initial policy; if you edit your policy again later, use the method described in the next section. Also, as with configuration files, you should remove the clear-text policy file from your system once you've created the binary file. If you need to refer to or edit the policy later, you can retrieve it with the command: twadmin --print-polfile > mypol.txt The last step in setting up Tripwire for the first time on a system is to create (initialize) its database: tripwire --init
Use the --init directive only when creating a new database. We'll see how to update the database in the next section. 11.2.3 Running Tripwire Checks and UpdatesOnce you've got a database installed, you can run periodic checks against it. At its simplest, the command to do so is the following: tripwire --check This compares all protected files against the hash database and prints a report both to the screen and to a binary file. The report can be viewed again with the command: twprint --print-report --report-level N --twrfile /path/file where N is a number from 0 to 4, 0 being a one-line summary and 4 being a full report with full details; /path/file is the full path and name of the latest report. By default, the report will reside in /var/lib/tripwire/report, with a time-/date-stamp appended to its filename (e.g. /var/lib/tripwire/report/myron.polkatistas.org-20020311-221057.twr). To have Tripwire automatically email the report to all recipients specified in the policy, you can run your check like this: tripwire --check --email-report Note that the report will still be printed to standard output and saved in /var/lib/tripwire/report, in addition to being emailed. This is a handy command to run as a cron or anacron job: since it doesn't require you to authenticate with your site or local key, it can be run in this mode unattended. If you've just installed the Tripwire RPM on a Red Hat 7 system, your system is already set up with such a cron job: the Tripwire RPM installs the script /etc/cron.daily/tripwire-check. (See Example 11-6, modified to allow for Tripwire paths besides /var/lib/tripwire). If you've installed Tripwire from source or otherwise need to set up the cron job yourself, add this script to /etc/cron.daily manually. Example 11-6. Script for automated Tripwire checks#!/bin/sh HOST_NAME=`uname -n` TWHOME = /var/lib/tripwire if [ ! -e $TWHOME/${HOST_NAME}.twd ] ; then echo "**** Error: Tripwire database for ${HOST_NAME} not found. ** **" echo "**** Run "/etc/tripwire/twinstall.sh" and/or "tripwire --init". ** **" else test -f /etc/tripwire/tw.cfg && /usr/sbin/tripwire --check fi If you've configured the emailto attribute in your Tripwire policy, you may wish to edit the second-to-last line of the tripwire-check script so that Tripwire emails its results and suppresses its standard output (so you don't receive email both from Tripwire and from crond): test -f /etc/tripwire/tw.cfg && /usr/sbin/tripwire --check --email-report --no-tty- output --silent Here's the same Tripwire command, this time in standard crontab format (and with short-form tripwire directives due to the length of the line): 30 1,5,14 * * * /usr/sbin/tripwire -m c -M -n -s I highly recommend you schedule Tripwire checks to run at least daily — better still, several times per day. Hourly may even make sense on systems that are at high risk (e.g., publicly accessible web servers). But if you run Tripwire that frequently, you'll definitely want to be judicious with regard to the number of files Tripwire checks, especially if your hardware isn't very fast: the cryptographic computations Tripwire uses can be both time- and CPU-consuming. If that becomes a problem, you may need to replace some of the directories in your policy with lists of specific files (e.g., rather than all of /usr/bin, do checks on /usr/bin/du, /usr/bin/find, etc.). The sidebar "Which Files and Directories Should I Check?" lists the bare-minimum files I recommend checking. If you use this technique, you can still include a line for the directory itself; just set recurse=0. This will cause Tripwire to check the directory's size, modification time, and other attributes, just not its contents. Changes to files in that directory that are not specifically checked will still trigger a violation (i.e., by causing their parent directory's modification time to change). 11.2.3.1 Updating Tripwire's database after violations or system changesSo, what happens when Tripwire reports violations? First, you need to determine whether each violation resulted from legitimate system changes, from a too-restrictive Tripwire policy, or from skullduggery. Unless your system is high profile, high risk, or just plain unlucky, the vast majority of reported violations will be false positives — i.e., not skullduggery related. If all the violations reported by Tripwire are from legitimate changes, you'll want to update the Tripwire database to reflect your new system state. This way, you don't have to see the same violations again next time. (You may want to tweak your policy too, but more on that shortly.) There are two ways to do this. The first is to run the command tripwire in update mode: tripwire --update --twrfile /path/to/report/myhost-date.twr where the last argument is the absolute path to the report you wish to use as the basis for this update; by default, Tripwire saves its reports to /var/lib/tripwire/report. Running tripwire in update mode opens the specified report with your editor of choice (as indicated in tw.cfg). This allows you to review the items Tripwire has flagged with an x as needing to be updated in its database. By default, all changed files will be flagged; you can leave them that way or unflag them as you see fit. When you exit the editing session, Tripwire will update the attributes and hashes in its database accordingly. Example 11-7 shows an excerpt from a tripwire -- update session. Example 11-7. Updating the Tripwire database (session excerpt)Remove the "x" from the adjacent box to prevent updating the database with the new values for this object. Modified: [x] "/home/mick/www" In Example 11-7, if I delete the x from the entry, exit the editor, and run a check, the change to /home/mick/www will be reported again; the database will not have updated to reflect this change. In short, if the change is legitimate, leave the x there. If it isn't or you're not sure, remove the x. The second way to update the Tripwire database is by doing the actual check in "interactive" mode, which immediately triggers an update session after the check finishes. Thus, the single command: tripwire --check --interactive is equivalent to these two commands: tripwire --check tripwire --update --twrfile /path/to/reportname.twr but with the added advantage of saving you the trouble of looking up the report's filename (which, since it includes a timestamp, isn't easily guessed). Being interactive, of course, this method can't be used for automated checks (e.g., cron jobs). (Updating the Tripwire database should never be done unattended, even though it's possible. You'll never hear how from me, though; it's that dumb of an idea.) 11.2.4 Changing Tripwire's PolicyI needn't bother repeating my mantra "some false positives are okay, no false negatives are!" But after your first Tripwire check or two, you'll probably want to adjust your Tripwire policy to exclude some things, include others, and watch still others less closely. Earlier, I mentioned that the twadmin command should be used to install only the initial policy, not updated policies. If you need to change your Tripwire policy after the database has been initialized (i.e., after you've run tripwire -- init), use the following commands to dump, edit, and install it again (Example 11-8). Example 11-8. Dumping, editing, and reinstalling Tripwire's policytwadmin --print-polfile > mypolicy.txt # dump current installed policy vi mypolicy.txt # make changes to policy ... tripwire --update-policy mypolicy.txt # install the updated policy When you use the -- update-policy directive, Tripwire will parse the specified policy text file, generate a new database, and compare all records that the old and new databases have in common. If those records match, Tripwire will encrypt, sign, and install your new policy and apply the corresponding changes to its database. If, however, any of the common records don't match, Tripwire will not update the policy or the database. You'll need to run a Tripwire check, followed by a database update (now is the perfect time to use tripwire -- check -- interactive) and then run the policy update again.
|