PDA

View Full Version : TIP: mtree HIDS script


anomie
September 15th, 2009, 21:10
Summary

I wrote a quick mtree HIDS script to supplement the concept I alluded to in this post (http://forums.freebsd.org/showpost.php?p=38966&postcount=5).

As a HIDS, this is nowhere near as flexible as some of the better third-party apps (e.g. AIDE), but it does offer the following benefits:

It uses only tools in the FreeBSD base system (sh, mtree, etc.).
It allows you to check and (re-)initialize just part (i.e. a single directory) of your HIDS db, or the entire thing, as needed.
It's quick to set up and easy to use.
When the autocheck is run as a cronjob, it will not send you needless chatter. It only makes noise when a difference is discovered.


Do not treat this alone as a comprehensive HIDS solution. A proper implementation would include facilities to keep the HIDS db on removable media and/or to encrypt and/or sign the HIDS db files.

(In my case, I am using this from a host system to check integrity on certain jail directories.)

Usage

# ./mtree-hids.sh help
Usage: ./mtree-hids.sh help
./mtree-hids.sh (init|check) directory
./mtree-hids.sh (autoinit|autocheck)
----------------------
help : prints this message
init : creates mtree database for a single directory
check : checks a single directory against its mtree database
autoinit : creates mtree databases for all directories
in /usr/local/mtreedb/dirlist.txt
autocheck : checks all directories in /usr/local/mtreedb/dirlist.txt
against their mtree databases


Be sure to manually create /usr/local/mtreedb/dirlist.txt. I recommend changing /usr/local/mtreedb ownership to root, and settings its mode with the octal 0700.

Example dirlist.txt (used by autoinit & autocheck)

# use absolute pathnames
/bin
/usr/bin
/usr/local/bin

/sbin
/usr/sbin
/usr/local/sbin

/lib
/usr/lib
/usr/local/lib

/libexec
/usr/libexec
/usr/local/libexec

/etc
/usr/local/etc

# add any others...

The script

#!/bin/sh

# Author: anomie
# Date : 2009-09-15

# Please see copyright at bottom of script

PATH=/bin:/usr/bin:/sbin:/usr/sbin

# ---------------------------------------------------------------------------
# Variable assignments
# ---------------------------------------------------------------------------

_keywords='uid,gid,mode,sha1digest,flags' # see mtree(8) manpages
_dbpath='/usr/local/mtreedb'
_dirlist='/usr/local/mtreedb/dirlist.txt'

# ---------------------------------------------------------------------------
# Functions
# ---------------------------------------------------------------------------

print_usage() {

echo "Usage: ${0} help"
echo " ${0} (init|check) directory"
echo " ${0} (autoinit|autocheck)"

}

print_help() {

echo "----------------------"
echo " help : prints this message"
echo " init : creates mtree database for a single directory"
echo " check : checks a single directory against its mtree database"
echo " autoinit : creates mtree databases for all directories"
echo " in ${_dirlist}"
echo " autocheck : checks all directories in ${_dirlist}"
echo " against their mtree databases"

}

audit_and_name_db() {

if [ -z "${_dir}" ] ; then
print_usage
exit 1
fi

if [ ! -d "${_dir}" ] ; then
echo "${0}: there is no directory ${_dir}"
exit 1
fi

#
# Give our mtree db file a name
#
_db="${_dbpath}/db-$(echo ${_dir} | tr '/' '_')"


}

audit_auto() {

if [ ! -f "${_dirlist}" ] ; then
echo "${0}: ${_dirlist} does not exist."
echo "Auto mode can not work without it."
exit 1
fi

if [ ! -s "${_dirlist}" ] ; then
echo "${0}: ${_dirlist} is empty."
echo "Nothing to do here."
exit 1
fi

}

create_db() {

echo "Creating new mtree db file for ${_dir}...."

mtree -p ${_dir} -k ${_keywords} -c > ${_db}

if [ ${?} -ne 0 ] ; then
echo "${0}: problem creating mtree db file for ${_dir}."
exit 1
fi

}

check_integrity() {
#
# Check directory integrity against existing mtree database
#
if [ ! -e "${_db}" ] ; then
echo "${0}: no mtree db found at ${_db}."
echo "Check your path, or init a new db file."
exit 1
fi

mtree -p ${_dir} -f ${_db} > ${_db}.tmp.output

_rc=${?}

if [ ${_rc} -eq 2 ] || [ -s "${_db}.tmp.output" ] ; then
echo '--------'
echo "WARNING: mtree found differences for ${_dir}"
echo '--------'
cat ${_db}.tmp.output
rm -f ${_db}.tmp.output

elif [ ${_rc} -ne 0 ] ; then
echo "${0}: error checking integrity of ${_dir}."
echo "(mtree exited with: ${_rc})"
exit 1
fi

#
# Clean up the empty file
#
rm -f ${_db}.tmp.output

}

create_db_auto() {

#
# Note that blank lines and comments (#) are silently ignored
#
for I in $(cat ${_dirlist} | egrep -v '^$|^#') ; do

_dir=${I}
audit_and_name_db
create_db

done

}

check_integrity_auto() {

#
# Note that blank lines and comments (#) are silently ignored
#
for I in $(cat ${_dirlist} | egrep -v '^$|^#') ; do

_dir=${I}
audit_and_name_db
check_integrity

done

}

# ---------------------------------------------------------------------------
# Main logic
# ---------------------------------------------------------------------------

#
# This first decision structure handles audits and some variable
# initialization
#
case "${1}" in

"help") print_usage
print_help
exit 0
;;

"init"|"check")
_dir="${2}"
audit_and_name_db
;;

"autoinit"|"autocheck")
audit_auto
;;

*) print_usage
exit 1
;;

esac

#
# This second decision structure does the actual work
#
case "${1}" in

"init") create_db
;;

"check") check_integrity
;;

"autoinit") create_db_auto
;;

"autocheck") check_integrity_auto
;;

*) exit 99 # how did you get here?
;;

esac

exit 0

# ---------------------------------
# Copyright (c) 2009 anomie
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.

Preliminary test cases look good. If I discover any bugs I'll post a patch here.

l2f
June 10th, 2011, 04:42
Hello,

A couple of years ago, I did the same thing from Dru Lavigne tips (BSD tips); ssh to the host, run mtree and retrieve the output to be stored in a safe place (with any digest that mtree supports, to be sure). Via crontab, re-run the same command, get back the output and do a diff to see what has changed. Simple solution, as you mentioned, with software from the base system of FreeBSD. ;)