Here's what remains to be done:
/usr/local/sbin. In that case, do (as root) from the
directory where stealth was compiled/unpacked:
install stealth /usr/local/sbin
options given to install(1) may restrict further use of stealth.
client under the subdirectory
/root/stealth/client.
Stealth reports should be sent to the user admin@elsewhere, who is only
interested in a short notice of changes, as the full report can always be read
elsewhere. So, a support-script is developed to further filter the report
generated by stealth.
As the sha1sum program on the client may be hacked, it is a good idea to
transfer the client's sha1sum program to the controller first, in order to
check that program locally, before trusting it to compute the sha1sums of the
client's files. The same holds true for any libraries and support programs
(like find) that are used intensively during integrity scans
Sha1sum checks should be performed on all setuid and setgid files on the
client, and in order to be able reach all files on client,
root@controller is allowed to login to the root@client account using a
password-less ssh connection.
Furthermore, sha1sum checks should be performed on all configuration files,
living under /etc and on the file /usr/bin/find which is used
intensively to perform the checks.
The required policy file is constructed as follows, per section:
DEFINE SSHCMD /usr/bin/ssh root@client -T -q exec /bin/bash --noprofile
DEFINE EXECSHA1 -xdev -perm +u+s,g+s \( -user root -or -group root \) \
-type f -exec /usr/bin/sha1sum {} \;
The first DEFINE defines the ssh command to use: an ssh-connection
will be made to the root account at the client.
The second DEFINE shows the arguments for find(1) when looking for
all root setuid or setgid normal files. For all these files the sha1sum(1)
program should be run.
USE BASE /root/stealth/client
USE EMAIL admin@elswhere
USE MAILER /root/bin/stealthmail
USE MAILARGS "Client STEALTH report"
USE SSH ${SSHCMD}
/root/stealth/client
directory.
admin@elsewhere.
stealthmail), living in
/root/bin.
SSH-DEFINE.
USE directives can be used,
and were therefore not specified. They are:
USE DD /bin/dd
USE DIFF /usr/bin/diff
USE PIDFILE /var/run/stealth-
USE REPORT report
USE SH /bin/sh
First, we'll copy the client's sha1sum program to the controller. In practice, this should also include the shared object libraries that are used by sha1sum, as they might have become corrupted as well.
5.2.3.1: Obtain the client's sha1sum program
First, the sha1sum program is copied to a local directory
GET /usr/bin/sha1sum /root/tmp
This command must succeed.
5.2.3.2: Check the integrity of the client's sha1sum program
Next, we'll check the received sha1sum program, using our own:
LABEL \nCheck the client's sha1sum program
LOCAL CHECK LOG = local/sha1 /usr/bin/sha1sum /root/tmp/sha1sum
The LABEL command will write the label to the report file just before
the output of the sha1sum program is generated.
The LOCAL command will check the sha1sum of the program copied from the
client. The report is written on the file
/root/stealth/client/local/sha1. If this fails, the program will not
continue, but will alert admin@elsewhere that the check failed. This is of
course rather serious, as it indicates that either the controller's sha1sum
is behaving unexpectedly or that the client's sha1sum program has changed.
The sha1sum program may have changed due to a normal upgrade. If
so, admin@elsewhere will know this, and can (probably) ignore the
warning. The next time stealth is run, the (now updated) SHA1 value is
used, and it should again match the obtained SHA1 value from the copied
sha1sum program.
5.2.3.3: Check the client's /usr/bin/find command
The client will use it's find command intensively: find is a great
tool for producing files having almost any conceivable combination of
characteristics. Of course, the client's find command itself must be ok,
as well as the client's sha1sum program. Now that we know that the client's
sha1sum program is ok, we can use it to check the client's /usr/bin/find
program.
Note that the controller itself will not suffer any processing load here: only the client itself is taxed for checking the intergrity of its own files:
LABEL \nchecking the client's /usr/bin/find program
CHECK LOG = remote/binfind /usr/bin/sha1sum /usr/bin/find
5.2.3.4: Check the client's setuid/setgid files
Having checked the client's sha1sum and find programs, sha1 checksum
checks should be performed on all setuid and setgid files on the
client. For this we activate the sha1sum program on the client. In
order to check the setuid/setgid files, the following command is added to the
policy file:
LABEL \nsuid/sgid/executable files uid or gid root on the / partition
CHECK LOG = remote/setuidgid /usr/bin/find / ${EXECSHA1}
5.2.3.5: Check the configuration files in the client's /etc/ directory
Finally, the client's configuration files are checked. Some of these files
change so frequently that we don't want them to be checked. E.g.,
/etc/adjtime, /etc/mtab. To check the configuration file, do:
LABEL \nconfiguration files under /etc
CHECK LOG = remote/etcfiles \
/usr/bin/find /etc -type f -not -perm +6111 \
-not -regex "/etc/\(adjtime\|mtab\)" \
-exec /usr/bin/sha1sum {} \;
Here is the complete policy file that we've constructed so far:
DEFINE SSHCMD /usr/bin/ssh root@client -T -q exec /bin/bash --noprofile
DEFINE EXECSHA1 -xdev -perm +u+s,g+s \( -user root -or -group root \) \
-type f -exec /usr/bin/sha1sum {} \;
USE BASE /root/stealth/client
USE EMAIL admin@elswhere
USE MAILER /root/bin/stealthmail
USE MAILARGS "Client STEALTH report"
USE SSH ${SSHCMD}
USE DD /bin/dd
USE DIFF /usr/bin/diff
USE PIDFILE /var/run/stealth-
USE REPORT report
USE SH /bin/sh
GET /usr/bin/sha1sum /root/tmp
LABEL \nCheck the client's sha1sum program
LOCAL CHECK LOG = local/sha1 /usr/bin/sha1sum /root/tmp/sha1sum
LABEL \nchecking the client's /usr/bin/find program
CHECK LOG = remote/binfind /usr/bin/sha1sum /usr/bin/find
LABEL \nsuid/sgid/executable files uid or gid root on the / partition
CHECK LOG = remote/setuidgid /usr/bin/find / ${EXECSHA1}
LABEL \nconfiguration files under /etc
CHECK LOG = remote/etcfiles \
/usr/bin/find /etc -type f -not -perm +6111 \
-not -regex "/etc/\(adjtime\|mtab\)" \
-exec /usr/bin/sha1sum {} \;
root/stealth/client.
The first time stealth is run, it is usually run `by hand':
stealth policy
this will show all executed commands on the standard output, and will
initialize the reports. Running stealth this way for the just constructed
policy file results in the following output (lines were wrapped to improve
readability):
GET /usr/bin/sha1sum /root/tmp
LABEL \nCheck the client's sha1sum program
LOCAL CHECK LOG = local/sha1 /usr/bin/sha1sum /root/tmp/sha1sum
LABEL \nchecking the client's /usr/bin/find program
CHECK LOG = remote/binfind /usr/bin/sha1sum /usr/bin/find
LABEL \nsuid/sgid/executable files uid or gid root on the / partition
CHECK LOG = remote/setuidgid /usr/bin/find / -xdev -perm +u+s,g+s
\( -user root -or -group root \) -type f
-exec /usr/bin/sha1sum {} \;
LABEL \nconfiguration files under /etc
CHECK LOG = remote/etcfiles /usr/bin/find /etc
-type f -not -perm +6111 -not -regex "/etc/\(adjtime\|mtab\)"
-exec /usr/bin/sha1sum {} \;
LOCAL /usr/bin/scp -q root@client:/usr/bin/sha1sum /root/tmp
LABEL \nCheck the client's sha1sum program
LOCAL CHECK LOG = local/sha1 /usr/bin/sha1sum /root/tmp/sha1sum
LABEL \nchecking the client's /usr/bin/find program
CHECK LOG = remote/binfind /usr/bin/sha1sum /usr/bin/find
LABEL \nsuid/sgid/executable files uid or gid root on the / partition
CHECK LOG = remote/setuidgid /usr/bin/find / -xdev -perm +u+s,g+s
\( -user root -or -group root \) -type f
-exec /usr/bin/sha1sum {} \;
LABEL \nconfiguration files under /etc
CHECK LOG = remote/etcfiles /usr/bin/find /etc
-type f -not -perm +6111 -not -regex "/etc/\(adjtime\|mtab\)"
-exec /usr/bin/sha1sum {} \;
This all produces the following output:
The /root/bin/stealthmail is called with the following arguments:
"Client STEALTH report" admin@elswhere
The contents of the mailed report now is (the date will of course change, the next time stealth is run):
STEALTH (1.21) started at Mon Nov 24 10:50:30 2003
Check the client's sha1sum program
Initialized report on local/sha1
checking the client's /usr/bin/find program
Initialized report on remote/binfind
suid/sgid/executable files uid or gid root on the / partition
Initialized report on remote/setuidgid
configuration files under /etc
Initialized report on remote/etcfiles
Under /root/stealth/client the following entries are now available:
local: below this directory the reports of the locally performed
checks are found. Using our demo policy file, only one logfile is found
here: sha1, containing the client's SHA1 checksum of its /usr/bin/sha1sum
program:
45251e259bfaf1951658a7b66c328c52 /root/tmp/sha1sum
remote: at this directory the reports of the remotely performed
checks are found. Using our demo policy file, three files were created:
The file binfind, containing the checksum of the client's
/usr/bin/find program:
fc62fc774999584f1e29e0f94279a652 /usr/bin/find
The file etcfiles, containing the checksums of the client's
configuration files under /etc (shown only partially):
ced739ecb2c43a20053a9f0eb308b2b0 /etc/modutils/aliases
a2322d7e2f95317b2ddf3543eb4c74c0 /etc/modutils/paths
f9e3eac60200d41dd5569eeabb4eddff /etc/modutils/arch/i386
f07da2ebf00c6ed6649bae5501b84c4f /etc/modutils/arch/m68k.amiga
2893201cc7f7556160fa9cd1fb5ba56a /etc/modutils/arch/m68k.atari
...
bf73b4e76066381cd3caf80369ce1d0e /etc/deluser.conf
4cd70d9aee333307a09caa4ef003501d /etc/adduser.conf.dpkg-save
8c749353c5027d0065359562d4383b8d /etc/gimp/1.2/gtkrc_user
3ec404ec597ef5460600cccf0192f4d6 /etc/gimp/1.2/unitrc
8c740345b891179228e3d1066291167b /etc/gimp/1.2/gtkrc
The file setuidgid, containing the checksums of the client's
setuid/setgid root files (shown only partially):
030f3f84ec76a8181cca087c4ba655ea /bin/login
b6c0209547d88928f391d2bf88af34aa /bin/ping
5d324ad212b2ff8f767637ac1a8071ec /bin/su
344dbedc398d5114966914419ef53fcc /usr/bin/wall
27b045bd7306001f9ea31bc18712d8b7 /usr/bin/rxvt-xpm
...
3567b18ffc39c2dc6ec0c0d0fc483f4f /usr/lib/ssh-keysign
3383a7955ac2406311e9aa51c6ac9c2c /usr/X11R6/bin/X
3c99ea0425c6e0278039e16478d2fb57 /usr/X11R6/bin/xterm
d590f7f5b4d6ae61680692a52235d342 /usr/local/bin/setuidcall
4c17203d7d91ec4946dea2f0ae365d5b /sbin/unix_chkpwd
Of course, the checksums and the filenames shown are only for documentation purposes. At other systems this will show different files and/or checksums, no doubt.
/root/client/report New lines are always appended to
the /root/client/report file. It will never shorten, unless shorten by
the systems administrator at `controller'.
This file contains the following:
STEALTH (1.21) started at Mon Nov 24 10:50:30 2003
Check the client's sha1sum program
Initialized report on local/sha1
checking the client's /usr/bin/find program
Initialized report on remote/binfind
suid/sgid/executable files uid or gid root on the / partition
Initialized report on remote/setuidgid
configuration files under /etc
Initialized report on remote/etcfiles
This completes the information created by stealth during its first run.
root/stealth/client. If nothing has changed,
the log-files will remain unaltered. The new run will, however, produce some
new info on the file /root/client/report:
STEALTH (1.21) started at Mon Nov 24 10:50:30 2003
Check the client's sha1sum program
Initialized report on local/sha1
checking the client's /usr/bin/find program
Initialized report on remote/binfind
suid/sgid/executable files uid or gid root on the / partition
Initialized report on remote/setuidgid
configuration files under /etc
Initialized report on remote/etcfiles
STEALTH (1.21) started at Mon Nov 24 10:54:35 2003
Note that just one extra line was added: a timestamp showing the date/time
of the last run. The systems administrator may reduce/remove the report file
every once in a while to reclaim some disk space.
For the example, the following changes were made to the client's
files:
/etc/motd was changed
timezone~ was removed
/etc/motd.org was created
Next, stealth was once again run, producing the following output:
/root/client/report:
STEALTH (1.21) started at Mon Nov 24 10:54:35 2003
configuration files under /etc
ADDED: /etc/motd.org
< 945d0b8208e9861b8f9f2de155e619f9 /etc/motd.org
MODIFIED: /etc/motd
< 7f96195d5f051375fe7b523d29e379c1 /etc/motd
> 945d0b8208e9861b8f9f2de155e619f9 /etc/motd
REMOVED: /etc/timezone~
> 6322bc8cb3ec53f5eea33201b434b74b /etc/timezone~
Note that all changes were properly detected and logged in the file
/root/client/report.
STEALTH (0.90) started at Mon Oct 28 11:28:43 2002
configuration files under /etc
ADDED: /etc/motd.org
< 945d0b8208e9861b8f9f2de155e619f9 /etc/motd.org
MODIFIED: /etc/motd
< 7f96195d5f051375fe7b523d29e379c1 /etc/motd
> 945d0b8208e9861b8f9f2de155e619f9 /etc/motd
REMOVED: /etc/timezone~
> 6322bc8cb3ec53f5eea33201b434b74b /etc/timezone~
Note that the report only shows the info that was added to the
/root/client/report file.
The report itself could be beautified further. I myself use the following script to mail the report to the addressee:
#!/bin/bash
NAME=`basename $0`
tee /root/stealth/lastreport/$NAME | egrep -v '^([[:space:]]|[[:space:]]*$)' |
sort | uniq | mail -s $1 $2
For the client computer, this little script will write the mailed
report on a file /root/stealth/lastreport/client, overwriting its previous
contents, will remove all lines beginning with blanks (thus trimming away the
diff-generated lines), and will mail the sorted and uniqed lines
using mail. The addressee (admin@elsewhere) will receive the following
information:
ADDED: /etc/motd.org
MODIFIED: /etc/motd
REMOVED: /etc/timezone~
STEALTH (0.90) started at Mon Oct 28 11:28:43 2002
configuration files under /etc
In practice this suffices to have me take action if something out of the
ordinary has happened.
/root/stealth/client/remote/etcfiles
was recreated, saving the old file as
/root/stealth/client/remote/etcfiles.20021028-112851
As remarked earlier (see section 3.3), many
logfile.YYMMDD-HHMMSS files could eventually accumulate. As discussed in
section 3.3, it might be considered to remove old log files every
now and then.
If the client's sha1sum program itself is altered, a serious situation
has developed. In that case, further actions by stealth would be suspect,
as their results might easily be currupted. Checks will proceed, but a
warning is generated on the report file (and in the mail sent to
admin@elsewhere:
STEALTH (1.21) started at Mon Nov 24 10:54:35 2003
Check the client's sha1sum program
MODIFIED: /root/tmp/sha1sum
< fc62fc774999584f1e29e0f94279a652 /root/tmp/sha1sum
> 45251e259bfaf1951658a7b66c328c52 /root/tmp/sha1sum
*** BE CAREFUL *** REMAINING RESULTS MAY BE FORGED
configuration files under /etc
REMOVED: /etc/motd.org
> 945d0b8208e9861b8f9f2de155e619f9 /etc/motd.org
MODIFIED: /etc/motd
< 945d0b8208e9861b8f9f2de155e619f9 /etc/motd
> 7f96195d5f051375fe7b523d29e379c1 /etc/motd
(The report shows the removal of the previously added file motd.org,
and the modification of motd. These are real, as the original motd
file, modified earlier, was restored at this point).
/etc/cron.d/stealth could be created, containing a line like
(assuming stealth lives in /usr/sbin):
2,17,32,47 * * * * root test -x /usr/sbin/stealth && \
/usr/sbin/stealth -q /root/stealth/client.pol
This will start stealth 2 minutes after every hour. Alternate schemes
are left to the reader to design.
In general, randomizing events makes it harder to notice them.
stealth may start its tasks at a random point in time if its
-i flag (for random interval) is used. This flag expects an argument
in seconds (or in minutes, if at least an m is appended to the interval
specification). Somewhere between the time stealth starts and the
specified interval the scan will commence. For example, the following two
commands have identical effects: the scan is started somewhere between the
moment stealth was started and 5 minutes:
stealth -i 5min -q /root/stealth/client.pol
stealth -i 300 -q /root/stealth/client.pol
When the -d flag is given, the -i flag has no effect.
As another alternative, stealth my be started specifying the
--keep-alive pidfile option. Here, pidfile is the name of a file that
will contain the process id of the stealth process running in the background.
For example:
stealth --keep-alive /var/run/stealth -i 300 -q /root/stealth/client.pol
Now, cron(1) may be used to restart this process at indicated times:
2,17,32,47 * * * * root test -x /usr/sbin/stealth && \
/usr/sbin/stealth --rerun /var/run/stealth
As yet another alternative, the cron-job may activate a script performing
stealth's rerun, starting another stealth run if necessary. The
advantage of such an approach is that stealth is automatically started
after, e.g., a reboot. The following script expects two arguments (both of
which must be absolute paths). The first argument is the path to the
pidfile to use, the second argument is the path to the policy file to
use. The script is found in the distribution package as
/usr/share/doc/stealth/usr/sbin/stealthcron:
#!/bin/bash
PROG=`basename $0`
STEALTH=/usr/sbin/stealth
testAbsolute()
{
echo $1 | grep "^/" > /dev/null 2>&1 && return
echo "\`$1' must be absolute path"
exit 1
}
case $# in
(2)
testAbsolute $1
testAbsolute $2
if [ -x ${STEALTH} ] ; then
${STEALTH} --rerun $1
[ $? -eq 0 ] || ${STEALTH} --keep-alive $1 -q $2
fi
;;
(*)
echo "
$PROG by Frank B. Brokken (f.b.brokken@rug.nl)
Usage: $PROG [sleep] pidfile configfile
where:
pidfile: absolute path to pidfile to be used by ${STEALTH}
configfile: absolute path to configuration file to be used by ${STEALTH}
calls $STEALTH} --rerun pidfile.
If that fails, ${STEALTH} --keep-alive pidfile -q configfile is started.
"
exit 1
;;
esac
The script could be called from /etc/cron.d/stealth using a line like
22 8 * * * root test -x /usr/sbin/stealthcron && /usr/sbin/stealthcron
/var/run/stealth.target /usr/share/stealth/target.pol
Note that the command should be on a single line. It was spread out here
over two lines to enhance readability.
--resume were implemented. Both options require the
process-ID file of currently active stealth process as their argument.
For example, if a stealth process was once started using the command
stealth -q --keep-alive /var/run/stealth.small --repeat 900 \
/var/stealth/policies/small.pol
then the --suppress and --resume commands for this process should
be formulated as:
stealth --suppress /var/run/stealth.small
stealth --resume /var/run/stealth.small
The stealth process identified in the files provided as arguments to
the --suppress and --resume options is called the targeted stealth
process below.
The --suppress option has the following effect:
--resume (see below) and --terminate.
--suppress command
are ignored for the targeted stealth process;
--suppress pidfile' terminates.
--suppress pidfile' could be
specified nicely in such a pre-rotation section.
The --resume option has the following effect:
--resume implies --rerun.
--resume command are
again honored by the targeted stealth process, following the completion of
the --resume command.
--resume pidfile' terminates.
--suppress has been issued, all commands except
--resume and --terminate are ignored by the targeted stealth
process. While suppressed, the --terminate command is acknowledged as a
`emergency exit' which may or may not interfere with, e.g., an ongoing
log-rotation process. The targeted stealth process should not normally be
terminated while it is in its suppressed mode. The normal way to terminate a
stealth process running in the background is:
--terminate pidfile' command.
/usr/share/doc/stealth/usr/sbin/stealthcleanup is provided which can
be used to perform this cleanup. The script expects one argument: a resource
file defining the following shell variables:
directories: the directories below which the status files are
found;
gzdays: the number of days a status file must exist before it is
compressed using gzip(1);
rmdays: the maximum age (in days) of compressed status
files. Files exceeding this age are removed using rm(1).
stealthcleanup script as it is found in the binary distribution's
/usr/share/doc/stealth/usr/sbin directory:
#!/bin/bash
usage()
{
echo "
Usage: $0 rc-file
Where:
rc-file: resource file defining:
\`directories' - one or more directories containing status files
\`gzdays' - number of days status files may exist before they
are compressed
\`rmdays' - number of days gzipped status files may exist
before they are removed.
"
exit 1
}
error()
{
echo "$*" >&2
exit 1
}
[ $# == 1 ] || usage
# now source the configuration file
. $1
for x in $directories
do
cd $x || error "\`$x' must be a directory"
/usr/bin/find ./ -mtime +$rmdays -type f -regex '.*[0-9]+-[0-9]+\.gz' \
-exec /bin/rm {} \;
/usr/bin/find ./ -mtime +$gzdays -type f -regex '.*[0-9]+-[0-9]+' \
-exec /bin/gzip {} \;
done
exit 0
Assuming that the status files are written in
/var/stealth/target/local and /var/stealth/target/remote; that status
file should be compressed when older than 2 days and removed after 30 days,
the resource file is:
directories="
/var/stealth/target/local
/var/stealth/target/remote
"
rmdays=30
gzdays=3
Furthermore assuming that the resourcefile is installed in
/etc/stealth/cleanup.rc and the stealthcleanup script itself in
/usr/sbin/stealthcleanup, the stealthcleanup script could be called
as follows:
/usr/sbin/stealthcleanup /etc/stealth/cleanup.rc
Note that stealthcleanup may be called whether or not there are active
stealth processes, as stealth does not use status files anymore once
they have been written.
--resume
pidfile' could be specified nicely in such a post-rotation section.
Here is an example of a specification that can be used with
logrotate(1). Logrotate (on Debian systems) keeps its configuration files
in /etc/logrotate.d, and assuming there is a host target, whose report
file is /var/stealth/target/report, the required logrotate(1)
specification file (e.g., /etc/logrotate.d/target could be:
/var/stealth/target/report {
weekly
rotate 12
compress
missingok
prerotate
/usr/sbin/stealth --suppress /var/run/stealth.target
endscript
postrotate
/usr/sbin/stealth --resume /var/run/stealth.target
endscript
}
Using this specification file, logrotate(1) will
stealth --resume xxx will always start with another file
integrity scan.