Below, the term controller is used for the computer where stealth is started, while the term client is used for the computer that is scanned by stealth. The controller and the client could be the same computer, but normally they are different.
The policy file consists of three sets of data: define directives (starting with the keyword DEFINE), use directives (starting with the keyword USE) and commands.
Directives are written in capitals, and should appear exactly as written below: letter casing is preserved.
Blank lines and information beyond hash-marks (#) are ignored, while lines following lines terminating in backslashes (\ ) will be concatenated (en passant removing the backslashes). Initial white space on lines of the policy file is ignored.
DEFINE
directives can be used to define symbols for longer strings.
A DEFINE
directive is constructed as follows:
DEFINE name that what is defined by `name'Here,
name
following DEFINE
is the symbol that may be used in
USE
directives (see below) and commands
(see below).
DEFINE
symbols can be used in other DEFINE
symbols. However,
it is the responsibility of the author of the policy file to make sure that
(indirect) circular definitions are avoided. E.g., after:
DEFINE A ${B} DEFINE B ${A} DEFINE C ${C} USE MAILARGS ${A} ${B} ${C}
MAILARGS
will be expanded to
${A} ${A} ${C}
DEFINE name
is then inserted literally into
the USE
directive or command
.
Example:
DEFINE SSH /usr/bin/ssh frankbash@localhost -q DEFINE EXECSHA1 -xdev -perm +111 -type f -exec /usr/bin/sha1sum {} \;The symbols defined by
DEFINE
directives may consist of
letters, digits and the underscore character (_
).
In the definition of the symbol any character can be used. The
definition is, however, trimmed of initial or trailing blanks.
To insert a definition into a USE
directive or command
use the
${name}form. E.g.,
${EXECSHA1}
. Concrete examples will be given below.
USE
directives provide stealth with arguments which
may be conditional to a certain installation. The following USE directives
may be specified:
basedirectory
BASE defines the directory from where stealth operates. All relative path specifications are interpreted relative to BASE. By default this is the directory where stealth was started.
BASE and all other directories that are used below BASE
are created by stealth if not yet existing.
Example:
USE BASE /root/clientAll information generated by stealth is written in or below the directory
/root/client
.
<dd>
/bin/dd
as default, and defines the
location of the dd(1) program, both on the server and on the client. The
bin(1) program is used to copy files between the client and the controller
without opening separate ssh-connections. The program specified here is only
used by stealth for the PUT
and GET
commands, described below.
Example showing the default:
USE DD /bin/dd
path-to-diff
The DIFF specification uses /usr/bin/diff
as default,
and defines the location of the diff(1) program. The
diff(1) program is used to compare a formerly created logfile of an
integrity check to a newly created logfile.
Example showing the default:
USE DIFF /usr/bin/diff
address
The EMAIL specification defines the email-address to e-mail the client's integrity scan report to. Mail is only sent when information has changed.
Example showing the default:
USE EMAIL root
mailer
The MAILER specification defines the program that is used to send the mail to the EMAIL-address. By default this is /usr/bin/mail(1). The MAILER program is called as follows:
MAILER MAILARGS EMAIL(
MAILARGS
: see below). The information to be mailed is read from
MAILER
's standard input stream.
Example showing the default:
USE MAILER /usr/bin/mail
arguments
The MAILARGS specification defines the arguments to be
to be passed to the MAILER
program. By default this is
USE MAILARGS -s "STEALTH scan report"Note that blanks may be used in the subject specification: use double or single quotes to define elements containing blanks. Use
\"
to use a double
quote in a string that is itself delimited by double quotes, use \'
to use
a single quote in a string that is itself delimited by single quotes.
Subtle note: in a construction like
USE MAILARGS " 't was brillig " and 't went wellthe following arguments are passed to
MAILER
:
" 't was brillig "
and
't
went
well
reportfile
REPORT defines the name of the reportfile. Information is always appended to this file. For each run of stealth a time marker line is written to the report file. Such a marker line looks like this:
STEALTH (1.11) started at Mon Jun 16 12:57:26 2003Only when (in addition to the marker line) additional information was appended to the report file, the added contents of the report file are mailed to the mail address specified in the USE EMAIL specification.
Example showing the default:
USE REPORT report
interval: number interval-name
[,]
[count: number
][,]
[, zip: number [zip-program-path]
]
ROTATE defines the parameters stealth will use to rotate its report file. This USE specification supports three elements, the first of which is obligatory when USE ROTATE is specified. Note that the square brackets are not used in the specification, and indicate optional elements, which may or may not be specified:
interval: number interval-name
defines the time interval
until the report file is rotated. Rotation can be specified using an integral,
positive number, followed by hour
or hours
for hours, day
or
days
for days, week
or weeks
for weeks and month
or months
for months. By default no rotation takes place. If rotation is requested, the
current report file is moved to the file reportfile
.1, while existing
numbered reportfiles are moved to higher ordered numbers first (so, before
moving the current reportfile to reportfile
.1, an existing
reportfile
.1 is first moved to reportfile
.2, etc.).
count: number
defines the number of report files stealth
will eventually use. By default, if USE ROTATE is specified, there is no
practical limit to the number of report files stealth will create (in
these cases, another program supposedly controls the number of report files
that will eventually be used). External programs may freely manipulate all
report files that have been rotated by stealth, but they should not modify
the active report file (specified using the USE REPORT specification).
zip: number zip-program-path
defines the first of the rotated
files that should be compressed, using zip-program-path
to compress the
report files. By default, no compression is used, but if zip:
is
specified, the default program that will be used to compress a report file is
/bin/gzip. If another program is used, it should expect a filename as its
first argument, which will then be zipped to a new file receiving the
extension .gz, appended to the name that was provided as its first
argument. The original file is removed during the zipping-process.
Example showing a report interval of one week, using a total of 12 report
files, compressing all report files but the actual report file and its
predecessor (having filename reportfile
.1):
USE ROTATE interval: 1 week, count: 12, zip: 2 /bin/gzip
sh-specification
The SH specification uses /bin/sh
as default, and defines the
command shell used by the controller to execute local commands.
Example showing the default:
USE SH /bin/sh
ssh-specification
The SSH specification has no default, and must be
specified. Assuming the client trusts the controller (which is, after all,
what this program is all about; so this should not be a very strong
assumption), preferably the public ssh-identity key of the controller should
be placed in the client's root .ssh/authorized_keys
file, granting the
controller root access to the client. Root access is normally needed to gain
access to all directories and files of the client's file system.
In practice, connecting to a account using the sh(1) shell is
preferred. When another shell is already used by that account, one should make
sure that that shell doesn't setup its own redirections for standard input and
standard output. One way to accomplish that is for force the execution of
/bin/sh
in the USE SSH specification.
An example of an SSH
specification to scan a localhost is:
USE SSH root@localhost -T -q # root's shell is /bin/sh
The same, now explicitly using /bin/bash
:
USE SSH root@localhost -T -q exec /bin/bash # root uses another shell
Alternatively, --profile
can be specified to prevent any
profile-initialization:
USE SSH root@localhost -T -q exec /bin/bash --noprofile
stealth
to inspect localhost
is not
recommended, as it counters one of the main reasons for stealth
's
existence.
As yet another alternative, applicable only to localhost
, ssh
could be avoided altogether. In that case /bin/bash
or a comparable shell
may be specified with USE SSH
. For example:
# For stealth inspecting localhost: USE SSH /bin/bash --noprofile
Following the USE specifications, commands can be specified. The commands are executed in their order of appearance in the policy file. Processing continues until the last command has been processed or until a tested command (see below) returns a non-zero return value.
The following LABEL commands are available:
text
This defines a text-label which is written to the REPORT file, just before the output generated by the next CHECK-command. If the next CHECK-command generates no output, the label is not written to the REPORT-file. Once a LABEL has been defined, it is used until it is redefined by the next LABEL command. Use an empty LABEL command to suppress the printing of labels.
The text may contain \n
characters (two characters) which are
transformed to a newline character.
As noted, this clears a previously defined LABEL
command.
Examples:
LABEL Inspecting files in /etc\nIncluding subdirectories LABELThe second LABEL command clears the first label.
LOCAL commands can be used to specify commands that are executed on the controller itself. The following LOCAL commands are available:
command
Execute command
on the controller, using the SH command
shell. The command must succeed (i.e., must return a zero exit value).
Example:
LOCAL mkdir /tmp/clientThis command will create the directory
/tmp/client
on the controller.
command
Execute command
on the controller, using the SH command
shell. The command may or may not succeed.
Example:
LOCAL NOTEST mkdir /tmp/subdirThis command will create
/tmp/subdir
on the controller. The command
will fail if the directory cannot be created, but this will not terminate
stealth.
logfile command
Execute command
on the controller, using the SH command shell.
The phrase `LOG =' is optional.
If
the command does not succeed a warning message is written to the report
file. The warning message informs the reader that `remaining results might be
forged:
*** BE CAREFUL *** REMAINING RESULTS MAY BE FORGEDThis situation may occur, e.g., if an essential program (like
sha1sum
)
was transferred to the controller, and it was apparently modified since the
previous check. Processing continues, but remaining checks performed at the
client computer should be interpreted with extreme caution.
The output of this command is compared to the output of this command generated during the previous run of stealth. Any differences are written to REPORT.
If differences were found, the existing logfile
name is renamed to
logfile.YYYYMMDD-HHMMSS
, with YYYYMMDD-HHMMSS
the datetime-stamp at
the time stealth was run.
Over time, many logfile.YYMMDD-HHMMSS
files could be accumulated.
It is up to the controller's systems manager to decide what to do
with old datetime-stamped logfiles. For instance, the following script
will remove all stealth reports below the current directory that are
older than 30 days:
#/bin/sh FILES=`find ./ -path '*[0-9]' -mtime +30 -type f` if [ "$FILES" != "" ] ; then rm -f $FILES fi
The logfile
specifications may use relative and absolute paths. When
relative paths are used, these paths are relative to BASE. When the
directories implied by the logfile
specifications do not yet exist, they
are created first.
Example:
LOCAL CHECK LOG = local/sha1sum sha1sum /tmp/sha1sumThis command will check the SHA1 sum of the
/tmp/sha1sum
program. The
resulting output is saved at BASE/local/sha1sum
. The program must
succeed (i.e., sha1sum
must return a zero exit-value).
logfile command
Execute command
on the controller, using the SH command
shell. The phrase `LOG =' is optional.
The command may or may not succeed. Otherwise, the program acts
identically as the LOCAL CHECK ... command, discussed previously.
Example:
LOCAL NOTEST CHECK LOG=local/sha1sum sha1sum /tmp/sha1sumThis command will check the SHA1 sum of the
/tmp/sha1sum
program. The
resulting output is saved at BASE/local/sha1sum
. The program may or may
not succeed (i.e., sha1sum
may or may not return a zero exit-value).
Plain commands can be executed on the client computer by merely
specifying them. Of course, this means that programs called
LABEL
, LOCAL
USE
or DEFINE
, cannot be executed, since
these names are interpreted otherwise by stealth. It's unlikely that this
will cause problems. Remote commands must succeed (i.e., their return
codes must be 0).
Remote commands are commands executed on the client using the SSH
shell. These commands are executed using the standard PATH
set for the
SSH shell. However, it is advised to specify the full pathname to the
programs to be executed, to prevent ``trojan approaches'' where a trojan horse
is installed in an `earlier' directory of the PATH
-specification than the
intended program.
Two special remote commands are GET
and PUT
, which can be used to
copy files between the client and the controller. Internally, GET
and
PUT
use the DD
use-specification. If a non-default specification is
used, one should ensure that the alternate program accepts dd(1)'s if=,
of=, bs=
and count=
options. With GET
the options bs=, count=
and
of=
are used, with PUT
the options bs=, count=
and if=
are
used. Normally there should be no need to alter the default DD
specification.
The GET
command may be used as follows:
<client-path> <local-path>
client-path
at the client to local-path
at the controller. client-path
must be the full path of an existing file
on the client, local-path
may either be a local directory, in which case
the client's file name is used, or another file name may be specified, in
which case the client's file is copied to the specified local filename. If the
local file already exists, it is overwritten by the copy-procedure.
Example:
GET /usr/bin/sha1sum /tmp
The program /usr/bin/sha1sum
, available at the client, is copied to the
controller's /tmp
directory. If the copying fails for some reason,
any subsequent commands are skipped, and stealth terminates.
<client-path> <local-path>
client-path
at the client to local-path
at the controller. client-path
must be the full path of an existing file
on the client, local-path
may either be a local directory, in which case
the client's file name is used, or another file name may be specified, in
which case the client's file is copied to the specified local filename. If the
local file already exists, it is overwritten by the copy-procedure.
Example:
GET NOTEST /usr/bin/sha1sum /tmp
The program /usr/bin/sha1sum
, available at the client, is copied to the
controller's /tmp
directory. Remaining commands in the policy file are
executed, even if the copying process wasn't successful.
The PUT
command may be used as follows:
<local-path> <remote-path>
local-path
at the controller to
remote-path
at the client. The argument local-path
must be the
full path of an existing file on the controller. The argument remote-path
must be the full path to a file on the client. If the remote file already
exists, it is overwritten by PUT
.
Example:
PUT /tmp/sha1sum /usr/bin/sha1sum
The program /tmp/sha1sum
, available at the controller, is copied to the
client as usr/bin/sha1sum
. If the copying fails for some reason,
any subsequent commands are skipped, and stealth terminates.
<local-path> <remote-path>
local-path
at the controller to
remote-path
at the client. The argument local-path
must be the
full path of an existing file on the controller. The argument remote-path
must be the full path to a file on the client. If the remote file already
exists, it is overwritten by PUT
.
Example:
PUT NOTEST /tmp/sha1sum /usr/bin/sha1sum
Copy the file indicated by local-path
at the controller to
remote-path
at the client. The argument local-path
must be the full
path of an existing file on the controller. The argument remote-path
must
be the full path to a file on the client. If the remote file already exists,
it is overwritten by PUT
. Remaining commands in the policy file are
executed, even if the copying process wasn't successful.
Other commands to be executed on the client can be specified as follows:
command
Execute `command
' on the client, using the SSH command
shell. The command must succeed (i.e., must return a zero exit
value). However, any output generated by the command is ignored.
Example:
/usr/bin/find /tmp -type f -exec /bin/rm {} \;This command will remove all ordinary files at and below the client's
/tmp
directory.
command
Execute command
on the client, using the SSH command
shell. The command may or may not succeed.
Example:
NOTEST /usr/bin/find /tmp -type f -exec /bin/rm {} \;Same as the previous command, but this time the exit value of
/usr/bin/find
is not interpreted.
logfile command
Execute command
on the client, using the SSH command
shell. The phrase `LOG =' is optional.
The command must succeed. The output of this command is compared to the
output of this command generated during the previous run of stealth. Any
differences are written to REPORT. If differences were found, the existing
logfile
name is renamed to logfile.YYYYMMDD-HHMMSS
, with
YYYYMMDD-HHMMSS
the datetime-stamp at the time stealth was run.
Note that the command is executed on the client, but the logfile is kept on the controller. This command represents the core of the method implemented by stealth: there will be no residues of the actions performed by stealth on the client computers.
Several examples (note the use of the backslash as line continuation characters):
CHECK LOG = remote/ls.root /usr/bin/find / \ -xdev -perm +6111 -type f -exec /bin/ls -l {} \;All suid/gid/executable files on the same device as the root-directory (/) on the client computer are listed with their permissions, owner and size information. The resulting listing is written on the file BASE
/remote/ls.root
.
This long command could be formulated shorter using a DEFINE
:
DEFINE LSFIND -xdev -perm +6111 -type f -exec /bin/ls -l {} \; CHECK remote/ls.root /usr/bin/find / ${LSFIND}
Another example:
DEFINE SHA1SUM -xdev -perm +6111 -type f -exec /usr/bin/sha1sum {} \; CHECK remote/sha1.root /usr/bin/find / ${SHA1SUM}The SHA1 checksums of all suid/gid/executable files on the same device as the root-directory (/) on the client computer are determined. The resulting listing is written on the file BASE
/remote/sha1.root
.
logfile command
Execute command
on the client, using the SSH command
shell. The phrase `LOG =' is optional.
The command may or may not succeed. Otherwise, the program acts
identically as the CHECK ... command, discussed previously.
Example (using the same ${SHA1SUM}
)definition:
NOTEST CHECK LOG = remote/sha1.root /usr/bin/find / ${SHA1SUM}The SHA1 checksums of all suid/gid/executable files on the same device as the root-directory (/) on the client computer are determined. The resulting listing is written on the file BASE
/remote/sha1.root
. stealth will
not terminate if the /usr/bin/find
program returns a non-zero exit value.
Either by malicious intent or by accendent (as happened to me) the controller
may be a victim of a Denial of Service (DOS) attack. This DOS attack may
happen when the client (apparently) sends a never ending stream of bytes in
response to a GET
or REMOTE
command. One of my controllers once fell
victim to this attack when a client's power went down and the controller kept
on trying to read bytes from that client filling up the controllers disk....
This problem was of course caused by a programming error: while reading information from a client stealth failed to check whether the reading had actually succeeded. This bug has now been fixed, but an intentional DOS attack could still be staged along this line by a hacker who manages to replace, e.g., the find(1) command by a manipulated version which would continue to write information to its standard output stream. Without further precaution stealth would receive a never ending stream of bytes as its `report' thus causing its disk to fill.
To prevent this from happening stealth now offers the --max-size
command line option allowing the specification of the maximum size of a stream
of bytes received by stealth (e.g., a report or downloaded file). The
maximum is used for each individual download and can be specified in bytes
(using no suffix or the B
suffix), kilo-bytes (using K
), mega-bytes
(using M
) or giga-bytes (using G
). The default is set at 10M,
equivalent to the command line specification of --max-size 10M
.
If a file or report received from the client exceeds its maximum allowed size then stealth terminates after writing the following message to the report file (which is sent to the configured mail address):
STEALTH - CAN'T CONTINUE: `<name of offending file>' EXCEEDS MAX. DOWNLOAD SIZE (<size shown>) STEALTH - THIS COULD SIGNAL A SERIOUS PROBLEM WITH THE CLIENT STEALTH - ONE OR MORE LOG FILES MAY BE INVALID AS A RESULT STEALTH - *** INVESTIGATE ***Since a
--max-size
specification may cause stealth to terminate
while receiving the output of a (remotely run) command, an empty or partial
log file will be the result. Of course this partial result is spurious as it
is a direct result of stealth terminating due to a size violation.
After investigating (and removing) the reasons for the size violation a new stealth run using the previous log file as the latest baseline should show only expected changes.
For example, assume the following situation represents a (valid) state of logfiles:
etc stealth setuid stealth.20080316-105756Now stealth is run with
--max-size 20
, prematurely
terminating stealth. This results in the following set of logfiles:
etc stealth setuid stealth.20080316-105756 stealth.20080316-110215The file
stealth
now contains incomplete data with the (latest) file
stealth.20080316-110215
containing its previous contents.
Now the reasons for the size-violation should be investigated and
removed. It is suggested to move the file last saved
(stealth.20080316-110215
) to the file stealth
, as it represents the
state before the size violation was encountered. Following this stealth
should operate normally again.