README for the package "md5mon" by Serge Winitzki
Home page and contact information:
http://www.geocities.com/CapeCanaveral/Lab/5735/1/md5mon.html
Introduction
The package "md5mon" is a very basic security auditing script. It checks that certain files have not been modified. It uses "md5sum" or optionally "shasum" to compute checksums of files and reports any differences from previously recorded checksums. The checksum data can optionally be stored on a secure external medium (e.g. read-only floppy). Error logs can be optionally post-processed by a user-supplied script.
Depends on: sh which md5sum find tar gzip
Optional: shasum lsof netstat lsmod ...
Installation
Unpack the distribution into a directory such as /usr/local/md5mon, or any other directory. The necessary files include: "md5mon", "trustedsource", "sum.md5mon" and several "dirs_X", "files_X" and "exclude_X" files, where X is a number (0, 1, ...) The script will only use and modify files in the same directory where "md5mon" resides. You may choose the directory at an inconspicuous location, for example "/etc/X11/app-defaults/xyterm/", or you could make this directory and all files inside it readable only to root, or rename "md5mon" to something else, if you feel that it will improve security. (If you rename "md5mon" to something else, be sure to edit the "trustedsource" file accordingly.) Ancillary file names are also easily configurable by editing the script.
After unpacking the files, you will need to edit the ancillary files ("dirs_*", "files_*" and "exclude_*") to list files and directories that need to be monitored. You may optionally edit the script "trustedsource" to specify the commands you need to obtain the "trusted" checksums archive on your computer. The default configuration has "trustedsource" set to a simple copying of the checksums from another file ("sums.tar.gz") which is not a security improvement. Other possible configurations are: trusted source on floppy, on another computer or on the Web.
After making any changes, you need to run "md5mon -a" to reconcile changes. Finally, you can run "md5mon -u 0 1" to compute the integrity checksums of its ancillary files ("dirs_*", "files_*" and "exclude_*") and of all monitored files.
You may also edit the optional script "complain" which should perform any extra actions needed in case of mismatches found in files (a sample is provided). After this, you may want to add "md5mon" to your daily (or even hourly) cron schedule. A sample script "cron_md5mon" is supplied.
Synopsis of normal operation
In brief: You have a separate directory /opt/md5mon for the program and its data. You have set up monitoring levels 0 and 1 and "trusted source" on a write-protected floppy, and created the checksums by "md5mon -u 0 1". The normal operation of md5mon is to be called from a daily cron job: "/opt/md5mon/md5mon -q -c 0 1". You (root) get an email if any files are changed. Once in a while you need to change /etc/fstab or whatever and it triggers alarm. Then you have to reconcile: "/opt/md5mon/md5mon -a 0 /etc/fstab". You also have the write-protected floppy disk with the checksums file permanently sticking in the disk drive. The script will prompt you to unprotect it and then protect it again after the update. Once in a while you need to check that the script is still there, by running "sh -v /opt/md5mon/trustedsource" (this shows you every command and overwrites the script with its trusted copy, just in case.)
Features
There are two main actions: create the checksum lists and verify the checksums. There is also a "packaging" action and various partial update actions designed to simplify daily maintenance.
Files to monitor are selected by whole directories and/or individual files, and optionally filtered through exclusion lists to prevent scanning of inessential or frequently changing files.
Monitoring is happening at several "levels". A "level" is merely a separate set of files and directories to be monitored. The user might put a few of the most important files at one level and a larger number of less crucial files at another level, to save time when checking. For example, the default distribution has level 0 with all binaries, configuration files and system libraries, and level 1 with application libraries. Several levels can be checked at the same time.
The script will report all discrepancies found in checksums to a log file, and optionally call an external program to report the list of changed files, so it is suitable for cron jobs. In that case one could use the "-q" or "--quiet" option to prevent printing of messages unless mismatches are found.
The "packaging" action can be used to archive all current checksums together with the script and with copies of the "find" and "md5sum" binaries for secure storage. After packaging all your levels and storing a copy of the packaged archive in a secure location, you can be sure that you will definitely be able to detect any changes to the monitored files, should the need arise.
The script maintains its own integrity checksum in a small file which may be optinally stored on a read-only floppy media or on a remote computer and read at each checkup (the commands to obtain this file must be specified in an external script "trustedsource", examples are given). By just running the script "trustedsource" you overwrite the script and its checksum file with a securely stored data set. (Therefore, if you edit the script yourself, you need to "reconcile" all changes -- see the "--accept" action below.) The command "trustedsource -u" makes the necessary updates.
Usage
As an example, we consider operations at level 0 (exactly the same procedures apply to all other levels). You could start by editing the supplied sample files "dirs_0", "files_0" and "exclude_0" to select the files monitored at level 0. (The supplied files are perhaps sufficient for basic auditing purposes.) Note that all files in all subdirectories of the directories listed in "dirs_X" will be monitored, so including "/usr" in the file "dirs_0" may lead to monitoring a huge number of files and the operations may take a very long time, since all files will have to be read during an auditing action.
For instance, the file "dirs_0" could contain a list of common system binary directories, such as
/bin /boot /etc /sbin /usr/bin /usr/local/bin /usr/X11/bin /usr/sbin
(not necessarily in one line), while "exclude_0" might contain
/etc/mtab
.*~$
which will make the monitor ignore the frequently changing file "/etc/mtab" as well as any files ending with a "~". (Note that exclusion lists may contain several lines with a grep-compatible regular expression on each line, while the directory lists contain just plain directory names, perhaps with shell globbing.)
After editing the files "dirs_0", "files_0" and optionally "exclude_0" (if no "exclude_X" file is present, then all files are included; but at least one of "dirs_0" or "files_0" must be present) you can run "md5mon -u 0" or "md5mon --update 0" to create the checksum file. You can run the script from any directory as long as you specify the complete path (e.g. "/opt/md5mon-1.0/md5mon -u 0".) Note that you should execute the full update action only when you are sure that all the files you chose to monitor are pristine and authentic, for example, if you just finished compiling and installing them. The update action will create the file "sums_0" containing all checksums of the monitored files.
You may create any number of "levels" and run checks on them separately. For this you need to create the files "dirs_X" and optionally "exclude_X" where X will be the number of the level, and run "md5mon -u X" to create the checksum list for level X. The distribution comes with two preconfigured levels (0 and 1).
Reconciling changes
If you have edited the monitor lists "dirs_*", "files_*" or the exclusion lists "exclude_*", or customized the script itself after initially creating the checksums, the script won't run because its integrity information won't match. (This is a security feature to prevent tampering with the script.) One quick solution is to edit the integrity checksums table "sums.md5mon" and erase from it any checksums that don't match, then run the update action again. However, a full update may be time consuming. Similarly, if you have modified just a few of the monitored files and you are quite sure that the modified files are not trojaned,-- for instance, if you have just upgraded a couple of packages on your system,-- you may want to avoid running a long and potentially insecure update action. For this case, a "partial update" action can be used.
The partial update consists of (a) recomputing integrity information, ignoring a possible integrity mismatch, and optionally (b) updating the checksums of particular files specified by the user. The partial update action is specified by the "-a" or "--accept" option. For example, if you have edited the "md5mon" script itself, and you are quite sure that nobody else has edited it just before you, you can run "md5mon -a". The script will run and create a new integrity information file "sum.md5mon", even though the previous checksum fails. Similarly, if you are monitoring at level "0" the files "/etc/fstab", "/etc/hosts.deny" and maybe other system configuration files with "md5mon", and you have changed these files, you could now run
md5mon -a 0 /etc/fstab /etc/hosts.allow /etc/hosts.deny
(Full paths need to be specified.) This will avoid the long all-encompassing checksum of the entire level "0" and only update the sums for these three files. The script will print a message if one of its own files failed integrity checking during the --accept action but it will continue operation after that.
The same --accept action may be used to quickly add new files to the monitor list.
md5mon -a 0 /root/.shosts
The file name "/root/.shosts" (if it were not already monitored) will now be added to the "files_0" list and the checksum will be computed.
Sometimes there are many authorized changes to the system (e.g. upgrade of many packages) that result in a long list of changed or missing files. In this case you could use the --accept action with a list of files created during a --check action:
md5mon -a 0 `cat thislog_chk_0`
md5mon -e 0 `cat thislog_miss_0`
The first line, for instance, is equivalent to running "md5mon -a 0 file" on each file listed in the log file. Such blind reconciliation should be used with caution, since all errors and mismatches will be reconciled without a warning. Use this method only when you are sure that no unauthorized changes to the system have been made.
Finally, you may decide to stop monitoring some frequently changed files. For this an "--exclude" action is provided. For example, if you included the /etc directory into the monitoring list for level 0 but later discovered that /etc/mtab is frequently changing, you may want to exclude this file from monitoring. You say
md5mon -e 0 /etc/mtab
and this file will be excluded from monitoring by entering the file name into the exclude_0 list. Note that both the --accept and the --exclude actions modify the sums_* and sum.md5mon files.
Increasing security
Checksums are always kept in the same directory as the md5mon script, and made readable only to root. It may make sense to also store the checksums away from the computer. To make this easier you can use the "package" action. It creates a file such as "md5mon-x.y-YYMMDDHHMM.tar.gz" which includes all of your file lists and checksum lists as well as good copies of system utilities "find" and "md5sum" (i.e. exact copies of the utilities that were originally used for checksum computation). Package your level X using "md5mon -p X" and store the resulting file (md5mon-*.tar.gz) in a secure place.
Using "trusted source"
An even more secure option is to set up integrity checking from a "trusted source" each time you run md5mon. You can store md5mon's own checksum file ("sums.md5mon") on a read-only media such as a write-protected floppy disk, or on a remote computer to which you have secure access, or a trusted Web site. The script "trustedsource", if present, will be automatically called by md5mon. It is intended to read the checksum file from a "trusted source" each time you run md5mon and verify that neither the script itself nor any of the checksum files have been tampered with. To enable this, you will need to edit the top part of script before first use and insert the necessary commands. Some examples are given as comments and you may uncomment and edit them. It is important to make sure that if the "trusted source" is unavailable, the checksum file on disk remains untouched. The script will stop with an error message if its checksum fails.
The script "trustedsource" includes examples on how to set up "trusted source" on a floppy disk or on a remote computer. To prevent tampering with the script, the "trusted source" should include a copy of the script itself and of the "md5sum" program, or even a copy of the entire package of checksums, if it fits on a floppy.
Note that any changes to the scripts "md5mon", "trustedsource", or to any of its configuration files after the first update will trigger an integrity check failure. In that case you will have to run either "--update" or "--accept" again and while doing this you must be quite sure that files on your computer have not been compromised. If you run the "partial update" (the option "--accept"), you are somewhat less at risk, because checksums will be recomputed for only a limited number of files. Do not forget to copy the updated "sum.md5mon" file back to your trusted source after any updates made using --accept or --exclude actions! For updating the trusted source, the "trustedsource -u" action is provided. (It is executed automatically by "md5mon" after such actions.) However, since the details of obtaining the "trusted source" are highly system-dependent, only the floppy action is fully configured. You need to edit the "trustedsource" file yourself to configure the correct actions. Remember that executing "trustedsource" will overwrite "md5mon" and "trustedsource" itself with files stored in the "source", so be careful when debugging.
Security considerations
It is not the purpose of this script to prevent tampering with the computer, but only to detect it. An intruder could modify the "md5mon" script itself to ignore mismatches for some files. For that reason, it is recommended to keep a backup copy of the checksums in a secure place. You can use the "--package" action to prepare a complete archive with all checksums. You can later expand that archive manually, overwriting the current md5mon package files if they have been tampered, and run the checks. You could run the "trustedsource" script with a verbose option ("sh -v trustedsource") to see whether it actually obtains the checksums and overwrites the files.
Error reporting
"md5mon" prints the names of all files that do not match checksums or are missing, even in the "quiet" mode. It also maintains log files "log_X" where it cumulatively stores all errors ever encountered. Additionally, at each run the log files "thislog_chk_X" and "thislog_miss_X" are created with the lists of mismatched and missing files found during that run; the file "thislog_" will contain errors during integrity check. (If any of these files are not present after running "md5mon", it means there were no such errors.) A cron job could use these files to send a report to the administrator.
Optionally, a script or a program named "complain" could be created in the md5mon's directory, and if it exists it will be invoked by "md5mon" when any files are mismatched, as follows:
./complain "thislog_chk_X" "thislog_miss_X"
where "thislog_*_X" will be the names of the log files.
Quick command reference
At the moment the supported actions are: check, package, accept, exclude, and update.
To get quick help:
md5mon
md5mon -h
md5mon --help
To check that the files listed at levels 0, 2 and 5 are unmodified:
md5mon -c 0 2 5
md5mon --check 0 2 5
To check the files at level 0 but print no messages unless differences are found:
md5mon -q -c 0
md5mon --quiet --check 0
To create or update the checksum list at levels 4 and 1:
md5mon -u 4 1
md5mon --update 4 1
To package all files relevant to levels 0, 1, 4, and 5:
md5mon -p 0 1 4 5
md5mon --package 0 1 4 5
To use a somewhat more secure SHA checksum program "shasum" instead of "md5sum":
md5mon --sha -u 0 1 2
To make md5mon update its integrity information after you have edited the dirs_* or exclude_* files, or if you edited the script itself:
md5mon -a
md5mon --accept
To update integrity information and also update checksum information for just the selected files at level 1:
md5mon -a 1 /path/file1 /path/file2 /otherpath/file3
To permanently exclude several files from monitoring:
md5mon -a 1 /path/file1 /path/file2 ... md5mon --accept 1 /path/file1 /path/file2 ...
To manually copy integrity checksums from "trusted source":
trustedsource
To update "trusted source" with current integrity checksums:
trustedsource -u
trustedsource --update
Shortcomings in the current version of md5mon
- It is not determined whether a given md5mon installation uses md5sum or shasum. You have to remember that somehow and always use the --sha option if you have shasum checksums. Also, you cannot use md5sum for some levels and shasum for other levels, since the global checksum information needs to be stored in the same format for all levels.
- If self-check fails, nothing else is done -- could try to recover sums from trusted source and continue checking. Although it probably makes little sense at that point.
- If new files are dropped into monitored directories, md5mon doesn't mind them. (Should it?)
Version history
Version 1.0: initial release, actions "-c", "-u", "-p". Added "-a" action.
Version 1.1: changed -u action to avoid very long argument lists for $hash; added -e action.
Version 1.2: copying executables also from trusted source; creating a list of changed files and calling an external shell script "complain" if any errors are found; added "updatefloppy" script.
Version 1.3: added "files_*" lists for individual files; made "-a" add separate files to "files_*" lists for monitoring; improved documentation; separate "trustedsource" script; removed "updatefloppy" script.
