- Table of Contents
- Previous Chapter
- Next Chapter

# Chapter 4: The `policy' file

Stealth uses a policy file consisting of two sections, the second section is optional, and starts at a line merely containing `%%`.

Each policy file is uniquely associated with a host to be tested. Each host may have multiple policy files, though. In that case, each policy file defines its own set of checks to be performed.

- The policy file's first section consists of two sets of data: use directives (starting with the keyword USE) and commands.

- The (optional) second section starts at a line merely containing `%%`. Following this separating line several long option specifications can be entered (cf. section 5.2). Options specified on the command-line take priority over options specified in the policy file. Although the `--reload` option reloads the policy file, it will not change option values originally specified as command-line options.

  This section may contain specifications of the `skip-files` and `log` options. Relative file locations specified for these options are interpreted relative to the location of the policy file. E.g., if the policy file argument is specified as `/root/client/policy` then the specification `log: client.log` results in stealth writing its logs into the file `/root/client/client.log`.

The policy file's first section 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.

Blank lines and information beyond hash-marks (#) are ignored, while lines following lines terminating in backslashes (\ ) will be concatenated (en passant removing these backslashes). Leading white space on lines of the policy file is ignored.

## 4.1: DEFINE directives

`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,

- the `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 policy file's author 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}

- The text following `DEFINE name` is then inserted literally into the `USE` directive or `command`.

  Example:

          DEFINE  SSH         /usr/bin/ssh frank@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 characters (`_`). In the definition of the symbol any character can be used. However, initial and/or trailing blanks are removed from definitions.

  To insert a definition into a `USE` directive or `command` use the form

          ${name}

  E.g., `${EXECSHA1}`. Concrete examples are provided below.

## 4.2: USE directives

`USE` directives provide stealth with arguments which may be conditional to a certain installation. The following USE directives are supported:

- USE BASE `basedirectory`

  BASE defines the directory from where stealth operates. All relative path specifications in this section of the policy file are interpreted relative to BASE. By default this is the directory where stealth was started.

  If necessary, stealth creates all BASE and other directories below `BASE`.

  Example: using the specification

          USE BASE /root/client

  results in all information generated by stealth being written in or below the directory `/root/client`.

- USE DD `<dd>`
  The DD specification uses `/bin/dd` as default, and defines the location of the dd(1) program, both on the server and on the client. The DD program is used to copy files between the client and the monitor without creating separate ssh-connections. The DD program is only used by stealth for the `PUT` and `GET` commands, described below.

  Example showing the default:

          USE DD /bin/dd

- USE DIFF `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

- USE DIFFPREFIX `<prefix>`

  The DIFFPREFIX specification defines the size of the prefix added by the `DIFF` command to lines produced by commands executed through stealth. The default `/usr/bin/diff` program prefixes lines by either ``>` ' or ``<` '. The default value for `<prefix>` therefore equals 2.

  Example showing the default:

          USE DIFFPREFIX 2

- USE EMAIL `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

- USE MAILER `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

- USE MAILARGS `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.

  Subtlety: in constructions like

          USE MAILARGS " 't was brillig " and 't went well

  the following arguments are passed to `MAILER`:
  - `" 't was brillig "`
  - `and`
  - `'t`
  - `went`
  - `well`
  So, when single- and double-quoted strings overlap, the first string is taken as a string, and the information beyond the first string is thereupon interpreted.

- USE REPORT `<file-spec>`
  REPORT defines the name of the reportfile. Information is always appended to this file. At each stealth integrity scan a time marker line is written to the report file. Only when (in addition to the marker line) additional information is appended to the report file the added contents of the report file are mailed to the mail address specified in the USE EMAIL specification. When a relative file specification is used it is interpreted a location relative to the `USE BASE` specification.
  Example showing the default:
  `USE REPORT report`

- USE SH `<sh>`
  The SH specification uses `/bin/sh` as default, and defines the command shell used by the monitor to execute commands on itself. This must be an absolute path specification.
  Example showing the default:
  `USE SH /bin/sh`

- USE SSH `<user>`
  The SSH specification has no default, and must be specified. This must be an absolute path specification.

  Assuming the client trusts the monitor (which is after all what this program is all about, so this should not be a very strong assumption), preferably the public ssh key of the monitor should be placed in the client's root `.ssh/authorized_keys` file, granting the monitor 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 an account using the sh(1) shell is preferred. When another shell is already used by that account, one should make sure that its shell doesn't define 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, `--noprofile` can be specified to prevent any profile-initialization:

          USE SSH root@localhost -T -q exec /bin/bash --noprofile

In some installations stealth is used to inspect the monitor itself, even though this is not recommended, as it breaks one of the main reasons for stealth's existence. But in those situations (so, where stealth is used to monitor the integrity of the `localhost`), `/bin/bash` could be specified at the `USE SSH` directive. For example:

        # For stealth inspecting localhost:
            USE SSH /bin/bash --noprofile

## 4.3: Commands

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.

### 4.3.1: LABEL commands

The following LABEL commands are available:

- LABEL `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 printing labels.

  The text may contain `\n` characters (two characters) which are transformed to a newline character.

- LABEL

  As noted, this clears a previously defined `LABEL` command.

Examples:

        LABEL Inspecting files in /etc\nIncluding subdirectories
        LABEL

The latter LABEL command clears the text of the former LABEL command.

### 4.3.2: LOCAL commands

LOCAL commands can be used to specify commands that are executed on the monitor itself. The following LOCAL commands are available:

- LOCAL `command`

  Execute `command` on the monitor, using the SH command shell. The command must succeed (i.e., must return a zero exit value). Example:

          LOCAL mkdir /tmp/client

  This command creates the directory `/tmp/client` on the monitor.

- LOCAL NOTEST `command`

  Execute `command` on the monitor, using the SH command shell. The command may or may not succeed. Example:

          LOCAL NOTEST mkdir /tmp/subdir

  This command creates `/tmp/subdir` on the monitor. The command fails if the directory cannot be created, but this does not terminate stealth.

- LOCAL CHECK [LOG =] `logfile [pathOffset] command`

  Execute `command` on the monitor, using the SH command shell. The command must succeed. The output of this command is compared to the output of this command generated during the previous integrity check run by stealth.

  The phrase LOG = is optional. When a relative file location is specified at `<file-spec>` it is interpreted relatively to the `USE BASE` path specification.

  `PathOffset` is also optional. If specified it defines the (0-based) offset where path-names of inspected files start in lines produced by `<command>`. By default stealth assumes that the first occurrence of a forward slash defines the first character of the path-names of inspected files.

  For example, if diff-output looks like this:

          01234567890123456789012345678901234567890 (column offsets, not part of
                                                     the diff-output)

          33c33
          < 90d8b506d249634c4ff80b9018644567  filename-specification
          ---
          > b88d0b77db74cc4a742d7bc26cdd2a1e  filename-specification

  then the specification

          LOCAL CHECK logfile 36 command-to-be-executed

  informs stealth where to find the filename specifications in the diff-output. Using the standard `/usr/bin/diff` command, this offset equals 2 + the offset of the `filename-specification` found in `command-to-be-executed`.

  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 FORGED

  This situation may occur, e.g., if an essential program (like `sha1sum`) was transferred to the monitor, 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 monitor's systems manager to decide what to do with old datetime-stamped logfiles. For instance, the following script removes 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/sha1sum

  This 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).

- LOCAL NOTEST CHECK [LOG =] `logfile [pathOffset] command`

  Execute `command` on the monitor, using the SH command shell.

  The phrase LOG = is optional. When a relative file location is specified at `<file-spec>` it is interpreted relatively to the `USE BASE` path specification.

  The command may or may not succeed. Otherwise, the program performs exactly like the LOCAL CHECK ... command, discussed above.

  Example:

          LOCAL NOTEST CHECK LOG=local/sha1sum sha1sum /tmp/sha1sum

  This 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).

### 4.3.3: REMOTE commands

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 monitor. 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:

- GET `<client-path> <local-path>`
  Copy the file indicated by `client-path` at the client to `local-path` at the monitor. `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 monitor's `/tmp` directory. If copying fails for some reason, any subsequent commands are skipped, and stealth terminates.

- GET NOTEST `<client-path> <local-path>`
  Copy the file indicated by `client-path` at the client to `local-path` at the monitor. `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 monitor'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:

- PUT `<local-path> <remote-path>`
  Copy the file indicated by `local-path` at the monitor to `remote-path` at the client. The argument `local-path` must be the full path of an existing file on the monitor. 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 monitor, is copied to the client as `usr/bin/sha1sum`. If the copying fails for some reason, any subsequent commands are skipped, and stealth terminates.

- PUT NOTEST `<local-path> <remote-path>`
  Copy the file indicated by `local-path` at the monitor to `remote-path` at the client. The argument `local-path` must be the full path of an existing file on the monitor. 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 monitor to `remote-path` at the client. The argument `local-path` must be the full path of an existing file on the monitor. 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.

- NOTEST `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.

- CHECK [LOG =] `logfile [pathOffset] command`

  Execute `command` on the client, using the SSH command shell.

  The phrase LOG = is optional. When a relative file location is specified at `<file-spec>` it is interpreted relatively to the `USE BASE` path specification.

  `PathOffset` is also optional, and has the same meaning as for the `LOCAL CHECK` command, described above.

  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` being the datetime-stamp at the time stealth was run.

  Note that the command is executed on the client, but the logfile is kept at the monitor. This command represents the core of the method implemented by stealth: there will be no residues of the actions performed by stealth on 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`.

- NOTEST CHECK [LOG =] `logfile [pathOffset] command`

  Execute `command` on the client, using the SSH command shell.

  The phrase LOG = is optional. When a relative file location is specified at `<file-spec>` it is interpreted relatively to the `USE BASE` path specification.

  `PathOffset` is also optional, and has the same meaning as for the `LOCAL CHECK` command, described above. The command may or may not succeed. Otherwise, the program acts identically as the CHECK ... command, described above. 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.

### 4.3.4: Preventing Controller Denial of Service (--max-size)

Either by malicious intent or by accident (as happened to me) the monitor may be a victim of a (self-inflicted) Denial of Service (DOS) attack. This DOS attack may occur when the client (apparently) sends a never ending stream of bytes in response to a `GET` or `REMOTE` command. Once one of my monitors fell victim to this attack when a client's power went down and the monitor kept on trying to read bytes from that client filling up the monitor's 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 when, e.g., the find(1) command is somehow replaced by a manipulated version continuously writing information to its standard output stream. Without further precaution stealth would receive a never ending stream of bytes to be written to its `report' file, thus causing its disk to fill up.

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-105756

Now 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-110215

The file `stealth` now contains incomplete data with the (latest) file `stealth.20080316-110215` containing its previous contents.

The reasons for the size-violation should of course 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.

- Table of Contents
- Previous Chapter
- Next Chapter