NetBSD Veriexec subsystem

veriexec(8)
is a file integrity subsystem in NetBSD (introduced in 3.0). It is kernel
based, hence can provide some protection even in the case of a root compromise.

How it works

First of all (usually at boot time), Veriexec loads a specification file, also
called the signatures file, to the kernel. This file contains information
about files Veriexec should monitor, as well as their digital fingerprint
(along with the hashing algorithm used to produce this fingerprint), and
various flags that will be discussed later.

Then, whenever an application tries to open a file, there is a
kauth(9) check
before actually doing so if the application is permitted to do so. Veriexec
hooks in here and checks whether the file has the fingerprint as recorded in
the signature file. If not, it acts depending on its mode, e.g., it could deny
file access if the fingerprints mismatch.

To secure your system with veriexec, you need a kernel with the option
veriexec enabled (as it is in the default kernel), and you need support for
the algorithms you want to use (by default, all are activated). Then, you
decide which files you want to monitor, generate a signatures file and make it
load at boot.

Signatures file

An entry in the Veriexec signatures file looks like this:

/path/to/file algorithm fingerprint flags

With

/path/to/file is the absolute path to the monitored file.

algorithm is the used algorithm. It is one of MD5, SHA1, SHA256,
SHA384, SHA512, RMD160.

fingerprint is the signature of the file.

flags describe the monitoring type of the file, as described below.

Generating fingerprints

You can generate ASCII fingerprints for each algorithm using the following
tools:

veriexecgen

veriexecgen(8)
is a tool which automatically creates fingerprints for files or directories.
By default, it will create SHA256 fingerprints for /bin, /sbin, /usr/bin,
/usr/sbin, /lib, /usr/lib, /libexec and /usr/libexec and save them to
/etc/signatures.

You can also specify other algorithms and directories to be searched, e.g., you
might want to include fingerprints of the packages you installed (though you
have to be careful to recreate fingerprints on the next package update!).

veriexecctl

For controlling the database inside the kernel, you have the tool
veriexecctl(8).
It can be used for dumping the whole database (dump), flushing it (flush),
i.e., deleting all entries in the kernel's table, query an entry, etc.

Flags

Each entry may be associated with zero or more flags. Currently, these flags
indicate how the file the entry is describing should be accessed. Note that
this access type is enforced only in strict level 2 (IPS mode) and above.

The access types you can use are DIRECT, INDIRECT, and FILE.

DIRECT

DIRECT access means that the file is executed directly, and not invoked as an
interpreter for some script, or opened with an editor. Usually, most programs
you use will be accessed using this mode:

INDIRECT

INDIRECT access means that the file is executed indirectly, and is invoked to
interpret a script. This happens usually when scripts have a shebang (\#!)
magic as their first line. For example, if you have a script with the following
as its first line:

#!/bin/sh

And you run it as:

$ ./script.sh

Then /bin/sh will be executed indirectly -- it will be invoked to interpret
the script.

FILE

FILE entries refer to everything which is not (or should not) be an
executable. This includes shared libraries, configuration files, etc.
Everything you want to have monitored.

Veriexec allows you to specify more than one way to access a file in an entry.
For example, even though /usr/bin/perl is mostly used as an interpreter, it
may be desired to be able to execute it directly, too:

/usr/bin/perl MD5 914aa8aa47ebd79ccd7909a09ed61f81 DIRECT, INDIRECT

Shell scripts using \#! magic to be executable also require two access types:
We need them to be DIRECT so we can execute them, and we need them to be
FILE so that the kernel can feed their contents to the interpreter they
define:

/usr/src/build.sh MD5 e80dbb4c047ecc1d84053174c1e9264a DIRECT, FILE

To make it easier to create signature files, and to make the signature files
themselves more readable, Veriexec allows you to use the following aliases:

Alias

Expansion

PROGRAM

DIRECT

INTERPRETER

INDIRECT

SCRIPT

DIRECT, FILE

LIBRARY

FILE

Sample scripts for generating fingerprints are available in
/usr/share/examples/veriexecctl. After you've generated a signatures file,
you should save it as /etc/signatures, and enable Veriexec in rc.conf:

veriexec=YES

Strict levels

Since different people might want to use Veriexec for different purposes, we
also define four strict levels, ranging 0-3, and named learning, IDS,
IPS, and lockdown modes.

strict level 0 is the learning mode. In this level, Veriexec will act
passively and simply warn about any anomalies. Combined with verbose level
1, running the system in this mode can help you fine-tune the signatures
file. This is also the only strict level in which you can load new entries
to the kernel.

strict level 1 is the IDS mode (Intrusion Detection System Mode). Now,
Veriexec will deny access to files with a fingerprint mismatch. This mode
suits mostly to users who simply want to prevent access to files which
might've been maliciously modified by an attacker.

strict level 2, the IPS mode (Intrusion Prevention System Mode): This
level takes a step towards trying to protect the integrity of monitored
files. In addition to preventing access to files with a fingerprint
mismatch, it will also deny write access and prevent the removal of
monitored files, and enforce the way monitored files are accessed (as the
signatures file specifies).

strict level 3, named Lockdown mode is the most restricted mode.
Lockdown mode can be used in highly critical situations such as custom made
special-purpose machines, or as a last line of defense after an attacker
compromised the system and we want to prevent traces from being removed, so
we can perform post-mortem analysis. It will prevent the creation of new
files, and deny access to files not monitored by Veriexec.

It's recommended to first run Veriexec in strict level 0 and verbose level 1 to
fine-tune your signatures file and getting used to Veriexec, ensuring that
desired applications run correctly, and only then raise the strict level (and
lower the verbosity level). You can use /etc/sysctl.conf to auto raise the
strict level to the desired level after a reboot:

kern.veriexec.strict=1

Or you can also increase while the system is running (though this undermines
some of the security Veriexec provides):

sysctl -w kern.veriexec.strict=1

Veriexec and layered file systems

Veriexec can be used on NFS file systems on the client side and on layered file
systems such as nullfs. The files residing on these file systems need only be
specified in the /etc/signatures file and that the file systems be mounted
prior to the fingerprints being loaded.

If you are going to use layered file systems, you must ensure that you include
the fingerprint for files you want protected at every layer. If you fail to do
this, someone could overwrite a file protected by Veriexec by using a different
layer in a layered file system stack. This limitation may be removed in later
versions of NetBSD.

It's recommended that if you are not going to use layered file systems nor NFS,
then these features should be disabled in they kernel configuration. If you
need to use layered file systems, you have to follow the instructions in the
previous paragraph and ensure that the files you want protected have
fingerprints at all layers. You should also raise securelevel to 2 after all
mounts are done to prevent new layers from being mounted, which could
compromise Veriexec's protection:

kern.securelevel=2

Kernel configuration

To use Veriexec, aside from creating a signatures file, you need a kernel with
Veriexec enabled. It is already enabled in the default (GENERIC) kernel, but
if you built your own one, you have to uncomment the following line in the
configuration: