The version of Tripwire we discuss here is the version available under Debian. Tripwire is one of those products that began life as free software but was taken closed by its authors and is now a commercial product. You can find the commercial version at http://www.tripwire.com/ , and their product is at version 2.2.1. As with SSH, the open source version has been "adopted" and is also being actively developed. The open source version can be found at http://www.tripwire.org/ and is at version 2.3-47. The version in Debian 2.2 is 1.2-16. That's the version we cover here.
So just what is Tripwire? As its name suggests, it is a tool that alerts you when an intruder has been in your system. You provide a configuration file that names the files and directories to be watched, and then you specify how you want them watched (How much change is a change? Is a permission change a change, or only modification of the contents? Etc.). From then on, whenever a change is made to a monitored file, you will know it.
Tripwire works by using so-called message digest algorithms. This technology is similar to what underlies digital signatures. In fact, a digital signature is just a message digest that has been encrypted with a private key.
A message digest function is an algorithm constructed such that it is impossible for two different messages of a given length to have the same result. There are several such functions, and Tripwire uses quite a few of them. For those of you who care, Tripwire records all of the following functions on files included in the check:
· MD5
· Snefru
· CRC32
· CRC16
· MD4
· MD2
For those of you with a deep and abiding curiosity , you can find out about all of these functions in Bruce Schneier's excellent book, Applied Cryptography .
Tripwire stores all of these function results in a database file. This database should be moved on to a read-only file system. You then run Tripwire periodically to check files on the system against the database. Tripwire then generates a report of added, deleted, and changed files. This report should be checked. Expected changes should be used to update the database. Any unexpected change may indicate the prints and fibers of an intruder and should be investigated.
Tripwire began its existence at Purdue Unviversity, where it was a product of the Purdue Computer Science Department's COAST project. The COAST project is a research project dedicated to reliable computing. A great deal of research in computer security, software engineering, clustering, fail-over , and other topics of systems reliability have come from COAST. Tripwire is the brainchild of Gene Kim and Eugene Spafford.
Tripwire configuration is controlled by the /etc/tripwire/tw.config file. This file names all of the directories and files that are to be catalogued in the Tripwire database. You may make this as large or as small as you wish. Obviously, the more files you include, the better your protection against undetected intrusion. On the other hand, Tripwire will take longer to run, and the database will be larger.
Here's a sample configuration file for us to consider:
#
# tripwire.config for Linux/Debian machines
#
# I have tried to provide for a reasonable, minimal configuration file.
# You will have to tune this to your own taste and needs. -- pw.
#
# I even removed some more stuff to make it fit on a floppy. -- MM
# Define variables for searching devices, tmp directories, and logfiles
@@define DEVSEARCH E+ins
@@define TMPSEARCH E+ugp
@@define LOGSEARCH L-i
# Check all files:
# (We also mention some directories explicitly, because
# these are often put on a separate file system)
/ R
/usr R
/usr/local R
# Don't do these
# (/mnt is for temporarily mounted file systems;
# do a minimal check on /home anyway;
# no spool files except the crontab for root):
!/mnt
=/home
!/root
#
# I don't like /var since too many files change automatically. -- MM
#
#/var R
!/var
# Log files:
#/var/log @@LOGSEARCH
#/var/account @@LOGSEARCH
# /dev, /tmp and /var/tmp
#
/dev @@DEVSEARCH
=/tmp @@TMPSEARCH
=/usr/tmp @@TMPSEARCH
# No checksums for less important files (documentation, word lists):
# you might want to add /usr/X11R6/man if you have X installed
!/usr/doc
!/usr/dict
!/usr/info
!/usr/man
!/usr/src
# But do check the kernel sources
/usr/src/linux
For the moment, ignore the macro lines (the ones that start "@@"). The basic format is one entry per line. An entry may specify a file or a directory. When it names a directory, it really names the contents of that directory and all directories and files below it.
The basic action is to include the files specified by the entry in the Tripwire database. This behavior may be modified by a character prefix. Here are the valid character prefixes and their meaning:
Prefix | Description |
! | Exclude. Excludes the file. If the entry names a directory, this excludes the contents of the directory and all directories below it. |
= | Exclusive prune. Excludes all directories below the named directory, but includes the contents of the directory named. Has no effect if the entry names a file. |
Following the entry is an optional "select-flag" field. I like to call this field the "watch what" field. It specifies which aspects of the file are to be included in the signature database. This specifier begins with a "+" if the attributes are to be included, or with a "+" if the attributes are to be excluded. Here's the list of attributes:
Flag | Description |
p | Permission. Includes the permission and mode bits in the signature. Definitely yes! |
i | Inode. Include the inode number. (For those of you at home who don't know, inodes are the basic directory units of the file system. This can tell you if the file is moved, even if the rest of its attributes and contents are intact.) |
n | Number of links. As you probably know, more than one directory entry can point to a single physical file. This can be an important one to watch. Detecting when someone manages to get a link to an important file can matter. |
u | User ID. Detects changes in file ownership. Definitely yes! |
g | Group ID. Detects changes in group ownership. Definitely yes! |
s | Size. Size of file. Yes! |
a | Access time. This will tell you when someone looks at a file. For a very few files, yes, you care. For most, not. |
m | Modification time. This will tell you when somebody modifies a file. Note that this depends on the timestamps' not being interfered with. It's okay to use this, but don't rely on the modification timestamp without also including at least one of the strong file signatures (see later). |
c | inode creation/modification timestamp. This is usually the date/time the file was created. However, changes in the ownerships or permission bits of a file change this date. |
| Null signature. |
1 | MD5 message digest signature. |
2 | Snefru, the Xerox secure hash function. |
3 | CRC32 signature. This is a POSIX 1003.2 compliant cyclic redundancy check. |
4 | CRC-16. This is a 16-bit CRC algorithm, not the CCITT 16-bit algorithm. |
5 | MD4 message digest signature. |
6 | MD2 message digest signature. |
7 | SHA, secure hash algorithm, from NIST. |
8 | Haval. A strong 128-bit signature algorithm. |
Now, you may think that's rather an intimidating list. And you would be quite right too. Fortunately, there are some shortcuts to common combinations. All of the shortcuts are single-character uppercase flags that map to combinations of the base flags. Here are those special flags:
Shortcut | Flag Equivalent | Description |
R | +pinugsm12-ac3456789 | This is the default combination. It is for watching files that may be freely read but whose contents, ownerships, and permissions are not to change. |
L | +pinug-sacm123456789 | Log files. This is intended for files whose contents change frequently but whose ownerships, permissions, and locations are meant to be fixed. |
N | +pinusgsamc123456789 | Ignore nothing. This watches everything. |
E | -pinusgsamc123456789 | Ignore everything. This watches nothing. You might think this was equivalent to using the "!" prefix on an entry, but that's not so. These shortcuts may be combined with the other flags, so, for example, you might choose to watch only file access by using "E+a" after an entry. |
Tripwire also supports a preprocessor and macro system. We won't cover that here, except to point out its use in our sample file. The sample shows only the macro definition capability, which lets you name a bit of text and then use the name instead of the theoretically less readable text. Our sample uses this for a few basic flag combinations.
There are several "modes" in which the Tripwire executable may be run. The first is this one. Before Tripwire can do anything, you must create the database.
One tip: It doesn't do much good to create a Tripwire database on a system that is already compromised. Be certain. Create your Tripwire database on a freshly installed system that has not yet been on the Internet. Failing this, make every effort to be sure that your system has not been compromised. Look for setuid root programs that do not need to be setuid root. Look for accounts in /etc/passwd that you did not create. Look for files in /bin, /sbin. /usr/bin, /usr/sbin, /etc, and so on whose size and content don't match those on your distribution media. We don't have time or space to give you a full rundown on how to check your system integrity. For some help on this, look to such books as Practical Unix & Internet Security , by Garfinkle and Spafford, and Network Intrusion Detection, An Analyst's Handbook , by Stephen Northcutt.
To create your database based on the rules specified in your /etc/tripwire/tw.config, as root, run the following command:
# tripwire -init
The machine will chug, producing output that may look like this:
### Phase 1: Reading configuration file
### Phase 2: Generating file list
### Phase 3: Creating file information database
###
### Warning: Database file placed in ./databases/tw.db_mars.
###
### Make sure to move this file and the configuration
### to secure media!
###
### (Tripwire expects to find it in '/usr/lib/tripwire/
### databases'.)
It will create a directory called databases in the directory below that in which you run it. It is important to know that this file will do you absolutely no good there. You must move this file to the directory where Tripwire expects to find it.
As configured in Debian, this is /usr/lib/tripwire/databases, and, although the file is created root owned with permissions mode 400 (only readable by owner), this is not considered secure enough. You should immediately transfer the file to a read-only file system (write-protected floppy or CD-R media). You should then mount the file system at the /usr/lib/tripwire/databases directory.
Another tip: Run the init command while the machine is in single-user mode or at least while all of the machine's network interfaces are down. Why? Well, while the chance is small, it would be handy to an attacker to get a chance to modify the database file before it is transferred to the read-only media.
From time to time you will deliberately make changes to files that Tripwire is watching. If you have Tripwire set up to produce periodic reports (which you should), you probably won't want to continually receive reports for files you legitimately modified. That leads us to another mode in which Tripwire will run. That mode is called update. You can ask Tripwire to update its entry in the database for a specific file or directory. It's done like this:
# tripwire -update /etc
Don't trust a copy of the database you've left on your read/write media! Be sure to copy the read-only database to a root- writeable -only directory prior to running the update.
When you run the update, it will look like this:
### Phase 1: Reading configuration file
### Phase 2: Generating file list
Updating: update file: /etc
### Phase 3: Updating file information database
###
### Old database file will be moved to 'tw.db_mars.old'
### in ./databases.
###
### Updated database will be stored in './databases/tw.db_mars'
### (Tripwire expects it to be moved to '/usr/lib/tripwire/
### databases'.)
###
As before, this should be done in single-user mode or with all network interfaces down to prevent tampering with the database file while it is on a writeable file system. Also, as before, transfer this database to where Tripwire expects it to be, and this should be mounted on a read-only file system.
Now, you want to periodically execute Tripwire in yet a third mode. This mode, which is Tripwire's default mode, is integrity check mode. To run this manually, be logged in as root and run:
# tripwire
A good way to do this is with a daily cron job. Debian, in fact, runs the following script daily:
#!/bin/sh
DATABASE="/usr/lib/tripwire/databases/tw.db_'hostname'"
DATABASEGZIP="/usr/lib/tripwire/databases/tw.db_'hostname'.gz"
LOG=/var/log/tripwire
#
# set to user to actually send mail
MAILTO=mschwarz
#
#
# which binary do we use?
#
[ -f $DATABASE ] && TRIPWIRE=/usr/lib/tripwire/tripwire
[ -f $DATABASEGZIP ] && TRIPWIRE=/usr/lib/tripwire/ztripwire
#
# do not run if there is no database file
#
[ -z "$TRIPWIRE" ] && exit 0
#
# rotate the log file if it exists
#
if [ -f $LOG ]; then
savelog -p -g adm -m 640 -u root -c 7 $LOG > /dev/null
fi
#
# run the check
#
$TRIPWIRE -q > $LOG
#
# if the temporary file is empty, do not send mail
#
[ ! -s $LOG -o -z "$MAILTO" ] && exit 0
(cat <<EOF;
This is an automated report of possible file integrity changes, generated by
the Tripwire integrity checker.
Changed files/directories include:
EOF
cat $LOG
) /usr/bin/mail -s "File integrity report" $MAILTO
The report thus generated looks like this:
From root@schwarz Mon Mar 26 12:23:23 2001
Envelope-to: mschwarz@schwarz
Received: from root by mars.n0zes.ampr.org with local (Exim 3.12 #1
(Debian))
id 14hbeF-0000Pv-00
for <mschwarz@schwarz>; Mon, 26 Mar 2001 12:23:23 -0600
To: mschwarz@schwarz
Subject: File integrity report
Message-Id: <E14hbeF-0000Pv-00@mars.n0zes.ampr.org>
From: root <root@schwarz>
Date: Mon, 26 Mar 2001 12:23:23 -0600
Status: RO
This is an automated report of possible file integrity changes, generated by the Tripwire integrity checker.
Changed files/directories include:
added: -rwxr-xr-x root 98 Oct 19 13:51:31 1998 /usr/bin/cup
added: -rwxr-xr-x root 260 Oct 5 20:45:46 1998 /usr/bin/jlex
added: -rwxr-xr-x root 10128 Jan 4 07:55:10 2000 /usr/bin/pwgen
added: drwxr-xr-x root 4096 Mar 26 11:58:02 2001 /usr/share/CUP
added: drwxr-xr-x root 4096 Mar 26 11:58:02 2001
/usr/share/CUP/java_cup
added: -rw-r--r-- root 14331 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/Main.class
added: drwxr-xr-x root 4096 Mar 26 11:58:02 2001
/usr/share/CUP/java_cup/runtime
added: -rw-r--r-- root 1055 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/runtime/Symbol.class
added: -rw-r--r-- root 8564 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/runtime/lr_parser.class
added: -rw-r--r-- root 1587 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/runtime/virtual_parse_stack.class
added: -rw-r--r-- root 13125 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/CUP$parser$actions.class
added: -rw-r--r-- root 1215 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/action_part.class
added: -rw-r--r-- root 637 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/action_production.class
added: -rw-r--r-- root 363 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/assoc.class
added: -rw-r--r-- root 12367 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/emit.class
added: -rw-r--r-- root 651 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/internal_error.class
added: -rw-r--r-- root 3901 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/lalr_item.class
added: -rw-r--r-- root 3930 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/lalr_item_set.class
added: -rw-r--r-- root 9967 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/lalr_state.class
added: -rw-r--r-- root 1618 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/lalr_transition.class
added: -rw-r--r-- root 5201 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/lexer.class
added: -rw-r--r-- root 3326 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/lr_item_core.class
added: -rw-r--r-- root 3715 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/non_terminal.class
added: -rw-r--r-- root 702 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/nonassoc_action.class
added: -rw-r--r-- root 764 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/parse_action.class
added: -rw-r--r-- root 1077 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/parse_action_row.class
added: -rw-r--r-- root 2355 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/parse_action_table.class
added: -rw-r--r-- root 521 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/parse_reduce_row.class
added: -rw-r--r-- root 1390 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/parse_reduce_table.class
added: -rw-r--r-- root 16045 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/parser.class
added: -rw-r--r-- root 8191 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/production.class
added: -rw-r--r-- root 1072 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/production_part.class
added: -rw-r--r-- root 1241 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/reduce_action.class
added: -rw-r--r-- root 1223 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/shift_action.class
added: -rw-r--r-- root 1106 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/sym.class
added: -rw-r--r-- root 962 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/symbol.class
added: -rw-r--r-- root 1555 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/symbol_part.class
added: -rw-r--r-- root 2747 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/symbol_set.class
added: -rw-r--r-- root 2335 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/terminal.class
added: -rw-r--r-- root 2598 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/terminal_set.class
added: -rw-r--r-- root 560 Oct 19 13:51:31 1998
/usr/share/CUP/java_cup/version.class
added: -rw-r--r-- root 184 Oct 19 13:51:31 1998
/usr/lib/menu/cup
added: -rw-r--r-- root 192 Oct 5 20:45:46 1998
/usr/lib/menu/jlex
added: drwxr-xr-x root 4096 Mar 26 11:58:03 2001 /usr/lib/JLex
added: drwxr-xr-x root 4096 Mar 26 11:58:03 2001
/usr/lib/JLex/JLex
added: -rw-r--r-- root 653 Oct 5 20:45:46 1998
/usr/lib/JLex/JLex/CAcceptAnchor.class
added: -rw-r--r-- root 1003 Oct 5 20:45:46 1998
/usr/lib/JLex/JLex/CAccept.class
added: -rw-r--r-- root 2477 Oct 5 20:45:46 1998
/usr/lib/JLex/JLex/JavaLexBitSet.class
added: -rw-r--r-- root 1072 Oct 5 20:45:46 1998
/usr/lib/JLex/JLex/CAlloc.class
added: -rw-r--r-- root 819 Oct 5 20:45:46 1998
/usr/lib/JLex/JLex/CBunch.class
added: -rw-r--r-- root 809 Oct 5 20:45:46 1998
/usr/lib/JLex/JLex/CDTrans.class
added: -rw-r--r-- root 896 Oct 5 20:45:46 1998
/usr/lib/JLex/JLex/CDfa.class
added: -rw-r--r-- root 19984 Oct 5 20:45:46 1998
/usr/lib/JLex/JLex/CEmit.class
added: -rw-r--r-- root 2997 Oct 5 20:45:46 1998
/usr/lib/JLex/JLex/CError.class
added: -rw-r--r-- root 2129 Oct 5 20:45:46 1998
/usr/lib/JLex/JLex/CInput.class
added: -rw-r--r-- root 27688 Oct 5 20:45:46 1998
/usr/lib/JLex/JLex/CLexGen.class
added: -rw-r--r-- root 5413 Oct 5 20:45:46 1998
/usr/lib/JLex/JLex/CMakeNfa.class
added: -rw-r--r-- root 5984 Oct 5 20:45:46 1998
/usr/lib/JLex/JLex/CMinimize.class
added: -rw-r--r-- root 1370 Oct 5 20:45:46 1998
/usr/lib/JLex/JLex/CNfa.class
added: -rw-r--r-- root 5462 Oct 5 20:45:46 1998
/usr/lib/JLex/JLex/CNfa2Dfa.class
added: -rw-r--r-- root 642 Oct 5 20:45:46 1998
/usr/lib/JLex/JLex/CNfaPair.class
added: -rw-r--r-- root 1082 Oct 5 20:45:46 1998
/usr/lib/JLex/JLex/CSet.class
added: -rw-r--r-- root 3260 Oct 5 20:45:46 1998
/usr/lib/JLex/JLex/CSpec.class
added: -rw-r--r-- root 3173 Oct 5 20:45:46 1998
/usr/lib/JLex/JLex/CUtility.class
added: -rw-r--r-- root 1031 Oct 5 20:45:46 1998
/usr/lib/JLex/JLex/Main.class
deleted: drwx------ root 4096 Mar 23 09:23:18 2001
/usr/lib/tripwire/databases
deleted: -rw------- root 13318151 Mar 23 09:30:17 2001
/usr/lib/tripwire/databases/tw.db_mars
deleted: -rw------- root 12973625 Mar 23 09:23:28 2001
/usr/lib/tripwire/databases/tw.db_mars.old
changed: -rw-r--r-- root 3688 Mar 26 09:52:05 2001
/lib/modules/2.4.2/modules.dep
changed: drwxr-xr-x root 32768 Mar 26 11:58:03 2001 /usr/bin
changed: drwxr-xr-x root 4096 Mar 26 11:58:02 2001 /usr/share
changed: drwxr-xr-x root 32768 Mar 26 11:58:03 2001 /usr/lib
changed: drwxr-xr-x root 8192 Mar 26 11:58:03 2001 /usr/lib/menu
changed: drwxr-xr-x root 4096 Mar 26 11:27:24 2001 /etc
changed: -rw-r--r-- root 359 Mar 26 09:52:02 2001 /etc/motd
changed: -rw-r--r-- root 201 Mar 26 11:27:24 2001 /etc/mtab
changed: -rw-r--r-- root 45 Mar 25 23:46:36 2001 /etc/adjtime
changed: -rw-r--r-- root 1150 Mar 26 11:54:17 2001 /etc/passwd
changed: -rw-r--r-- root 394 Mar 25 20:38:45 2001 /etc/fstab
changed: -rw------- root 60 Mar 26 09:52:02 2001
/etc/ioctl.save
changed: drwxr-xr-x root 4096 Mar 26 11:58:11 2001 /etc/X11/twm
changed: -rw-r--r-- root 18315 Mar 26 11:58:11 2001
/etc/X11/twm/menudefs.hook
changed: drwxr-xr-x root 4096 Mar 26 11:58:11 2001
/etc/X11/WindowMaker
changed: -rw-r--r-- root 14127 Mar 26 11:58:10 2001
/etc/X11/WindowMaker/menu.hook
changed: -rw-r--r-- root 553 Mar 26 11:58:11 2001
/etc/X11/WindowMaker/appearance.menu
changed: -rw-r--r-- root 46 Mar 26 09:53:17 2001
/etc/resolv.conf
changed: -rw-r--r-- root 3822 Mar 26 09:52:05 2001
/etc/modules.conf
changed: -rw-r--r-- root 3822 Mar 26 09:52:05 2001
/etc/modules.conf.old
changed: -rw-r--r-- root 4843 Mar 26 11:52:58 2001
/etc/enscript.cfg
changed: prw-r----- root 4096 Mar 26 10:28:58 2001 /dev/xconsole
changed: -rw-rw-rw- root 0 Mar 26 10:13:07 2001 /dev/log
The report Tripwire gave us was rather lengthy. That's because I deliberately did a number of things to the system. Some were routine activities (installing a new software package, unmounting the read-only file system that contains the Tripwire database, and so on), and some were deliberate acts of pure evil! Now, I happen to know which were which. But if you did not, how would you go about finding out which were innocent activities and which were the acts of pure evil? There's no empirical way, but we can offer you a few suggestions.
First of all, when you see files added in normal system directories, you should know about it, because only root should be able to do this and only you (or your fellow system administrators) should have root authority. If this is your home desktop system and only you install software on it, be very suspicious of any such changes you don't recognize. If you are part of a group that has root authority and you don't know about these added packages, be suspicious, ask everyone else who has that privilege, and then take appropriate action. If you know (as I did) that you installed pwgen, cups, and JLex, then all is well with those added files.
One thing I would do systematically with added files, however, is to check to see if any of them are setuid root. Any new setuid root file is suspicious. If you don't know what this means, check out the man pages for the chmod command.
Next, the deleted files aren't really. As I said earlier, I had unmounted a copy of the Tripwire databases. Note that it was a copy. Had I unmounted the copy Tripwire used to compare, then the compare would not have worked!
That leaves the changed files. Some of the changed files are directories and correspond to some of the file adds and deletes. Some of the changes, such as /etc/enscript.cfg, were changes I made deliberately to the configuration of certain programs. Changes that should stand out are those made to critical system files. In this case, the ones I would be most concerned about are /etc/passwd, which defines users allowed to log in to the system, and /etc/modules.conf, which specifies loadable kernel modules. If you haven't changed your kernel configuration and this file has changed, I would definitely look into it.
Sure enough, these are the right things to check out. The /etc/modules.conf change turned out to be innocent, but the /etc/passwd change was more suspicious. Now, this wasn't a real crack attempt ”I made the change to make the point ”but have a look at what Tripwire caught:
...
...
root:x:0:0:root:/root:/bin/bash
telnetd:x:101:101::/usr/lib/telnetd:/bin/false
mysql:x:102:102:MySQL Server:/var/lib/mysql:/bin/false
ftp:x:103:103::/home/ftp:/bin/false
badboy:x:0:0::/:/bin/bash
...
...
I would be mighty suspicious of a second account that is user ID number zero. "badboy" is a mighty unusual account! This might be one of several ways an attacker might try to entrench him- or herself.