#! /bin/bash # /usr/local/sbin/mktripwire.sh VERSION=0.0.1 DEBUGME= # Set to "y" to output 2 of 23 rules, skip sleep TMP_FILE=/tmp/mktripwire.tmp # A Gentoo-oriented Tripwire Policy Generator # This script outputs tripwire policy text from gentoo configuration files # This script depends on equery (from gentoolkit) # As of 05 Nov 2010, this script is a work in progress # c.cboldt at gmail.com # # Generated layout is based on work by Darren Kirby # File: tripwire.pol.gentoo September 5, 2006 # http://bugs.gentoo.org/show_bug.cgi?id=34662 # # Darren Kirby's work is based on a tripwire policy for RedHat systems # Policy file for Red Hat Linux : V1.2.0rh : August 9, 2001 # # This tripwire policy generator executes a three-step process # - output a hardcoded header section # - generate file policies from lists of packages and files # - output a hardcoded footer section # (Includes a few legacy references from RedHat config file) # # The array variable contents can contain any non-ambiguous package # name and any file name. # The script checks whether or not a listed file or package is present. # # Improvments? run under other shell scripts / port to different code base # rationalize categories and security level settings # more excludelists # test emailto function # more complete/useful packages lists # find "gentoo locations" for the legacy material from RedHat policy file # better help messages and comments # better error and condition checking # automate creation of available package lists # (but categorization here is radically different from gentoo's "categories") ##### Start of Package and File Lists ##### Package Lists and Multile File Lists may be combined under one rule # RULENAME[] Unique Rule Name # PACKAGES[] Optional list of gentoo package names under this Rule Name # FILELIST[] Optional list of individual file names under this Rule Name # XWINLIST[] Optional list of individual files pertaining to X-Windows # SKIPINOD[] Optional list of individual files that are not persistent # REMARKS[] Optional Remarks associated with individual FileLists # IGNORELIST[] Optional list of files to ignore under this Rule Name # RECURSE[] defaults to empty - written file-by-file, applied to directories # EMAILTO[] defaults to empty - written rule-by-rule (MUST have leading comma) # SEVERITY[] defaults to SIG_HI = severity=100 # BINSECVALUE[] defaults to SEC_CRIT = $(IgnoreNone)-SHa # ETCSECVALUE[] defaults to SEC_CONFIG = $(Dynamic) # LOGSECVALUE[] defaults to SEC_LOG = $(Growing) RULENAME[0]='Tripwire Program Files' PACKAGES[0]='tripwire' BINSECVALUE[0]=SEC_BIN RULENAME[1]='[core|diff|find]utils procps' PACKAGES[1]='coreutils diffutils findutils procps' RULENAME[2]='Compression/Archiving Programs' PACKAGES[2]='tar bzip2 gzip zip unzip' RULENAME[3]='Networking Programs' PACKAGES[3]='net-tools iproute2 iputils iptables mgetty mingetty ppp wireshark nmap' RULENAME[4]='Miscellaneous Network Programs' PACKAGES[4]='tcpdump tcp-wrappers rsync samba distcc dhcpcd dnsmasq bind-tools knock telnet-bsd' ETCSECVALUE[4]=SEC_CRIT RULENAME[5]='Hardware and Device Programs' PACKAGES[5]="udev pciutils util-linux sysvinit psmisc kbd hdparm smartmontools \ lshw ethtool hotplug-base module-init-tools setserial dmraid" RULENAME[6]='Filesystem Programs' PACKAGES[6]="e2fsprogs progsreiserfs reiserfsprogs reiser4progs xfs nfs jfs \ pax-utils sysfsutils autofs lvm2 mdadm" RULENAME[7]='Miscellaneous File Programs' PACKAGES[7]="gawk grep patch cpio file lsof gettext groff less man ncurses slang \ sed slocate patchutils debianutils" RULENAME[8]='Toolchain Programs' PACKAGES[8]='gcc binutils glibc make autoconf automake' RULENAME[9]='Security Related Programs' PACKAGES[9]='shadow pam openssl openssh gnupg' RULENAME[10]='Email Related Programs' PACKAGES[10]='sendmail postfix ssmtp mailx procmail dovecot clamav spamassassin' EMAILTO[10]='"root@localhost"' RULENAME[11]='P2P Related Programs' PACKAGES[11]='ejabberd jabberd jabberd2 mu-conference' RULENAME[12]='WWW Related Programs' PACKAGES[12]='apache bozohttpd lighttpd mini_httpd thttpd' RULENAME[13]='Shell Binaries' PACKAGES[13]='bash zsh csh tcsh sash busybox screen perl python ruby' BINSECVALUE[13]=SEC_BIN RULENAME[14]='Editor Programs' PACKAGES[14]='nano joe vim ed emacs' RULENAME[15]='Gentoo Specific Binaries' PACKAGES[15]='portage portage-utils gentoolkit baselayout eix paludis' RULENAME[16]='System Boot Files' PACKAGES[16]='grub lilo' FILELIST[16]='/boot/* /lib/modules' REMARKS[16]='Contents of /boot directory are safer on an unmounted partition' RULENAME[17]='System Action and Logging' PACKAGES[17]='vixie-cron syslog-ng xinetd' ##### End of package lists ##### ##### Some File Lists cribbed from RedHat policy file RULENAME[18]='Critical Devices' FILELIST[18]="/dev/kmem /dev/mem /dev/null /dev/zero \ /dev/log /dev/cua0 /dev/console \ /dev/tty[123456789] /dev/tty1[012] \ /dev/urandom /dev/initctl /proc/*" REMARKS[18]='RedHat config singled out kmem, mem, null, zero. Also was recurse=false' # for i in `locate etc*[lL]ocal` # do [ -z "`equery -q belongs -e $i`" ] && echo " $i \\" # done RULENAME[19]='Local Config Files' FILELIST[19]="/etc/bash/bashrc.local \ /etc/dnsmasq-local.conf \ /etc/host-local-block \ /etc/host-banner-ads \ /etc/hosts \ /etc/hosts.allow \ /etc/hosts.deny \ /etc/dovecot/dovecot-local.conf \ /etc/lilo.conf \ /etc/ppp/chap-secrets \ /etc/ppp/ip-up.d/00-local.sh \ /etc/ppp/ip-down.d/00-local.sh \ /etc/rkhunter.conf.local \ /etc/screenrc-local \ /etc/syslog-ng/syslog-local.conf \ /etc/udev/rules.d/10-local.rules \ /etc/env.d/00Local" RULENAME[20]='User Libraries' FILELIST[20]='/usr/lib /usr/local/lib' REMARKS[20]='Remainder of system libraries and binaries' SEVERITY[20]=SIG_MED BINSECVALUE[20]=SEC_BIN RULENAME[21]='Other OS Bin and Lib' FILELIST[21]='/bin /lib' BINSECVALUE[21]=SEC_BIN RULENAME[22]='User Binaries' FILELIST[22]='/sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin' SEVERITY[22]=SIG_MED RECURSE[22]='(recurse = 1) ' # Root User directory is "different." # Roughly using RedHat legacy structure, comments, etc. RULENAME[23]='Root User Directory' REMARKS[23]='X-Windows should not be run as Root User!' FILELIST[23]="/root /root/.ssh /root/.gnupg \ /root/.bashrc /root/.bash_profile /root/.bash_logout \ /root/.cshrc /root/.tcshrc /root/.screenrc \ /root/.mc /root/.ncftp \ /root/Mail /root/mail \ /root/.pinerc /root/.pinepwd /root/.mailcap \ /root/.addressbook.lu /root/.addressbook \ /root/.amandahosts /root/.elm \ /root/.config /root/.fltk /root/.links \ /root/.esd_auth" XWINLIST[23]="/root/.ICEauthority /root/.xsession-errors /root/.Xresources /root/.Xmodmap \ /root/.fvwm /root/.fvwmrc \ /root/.sawfish \ /root/.gconf /root/.gconfd \ /root/.gnome /root/.gnome_private /root/.gnome-desktop /root/.qt" SKIPINOD[23]="/root/.Xauthority " IGNORELIST[23]="/root/.lesshst /root/.bash_history \ /root/.aumixrc /root/.calc_history \ /root/.enlightenment \ /root/.fonts.cache-1 \ /root/.lynx_cookies \ /root/.sc_history \ /root/.stack.wcd /root/.treedata.wcd /root/wcd.go" ########### End Package Lists and RuleName Definitions make_header () { echo " #########################################################################" echo " # #" echo " # Tripwire Policy File for Gentoo Linux #" echo " # #" echo " #########################################################################" echo echo echo " # Generated by $0 Version $VERSION" echo " # `date '+%B %e, %Y'`" echo echo echo " #########################################################################" echo " # #" echo " # Global Variable Definitions #" echo " # #" echo " # These are defined at install time by twinstall.sh #" echo " # #" echo " #########################################################################" echo echo '@@section GLOBAL' echo 'TWROOT="/usr/sbin" ;' echo 'TWBIN="/usr/sbin" ;' echo 'TWPOL="/etc/tripwire" ;' echo 'TWDB="/var/lib/tripwire" ;' echo 'TWSKEY="/etc/tripwire" ;' echo 'TWLKEY="/etc/tripwire" ;' echo 'TWREPORT="/var/lib/tripwire/report" ;' echo "HOSTNAME=\"`hostname`\" ; # Should be the hostname of this system" echo echo '@@section FS' echo 'SEC_CRIT = $(IgnoreNone)-SHa ; # Critical files that cannot change' echo 'SEC_SUID = $(IgnoreNone)-SHa ; # Binaries with the SUID or SGID flags set' echo 'SEC_BIN = $(ReadOnly) ; # Binaries that should not change' echo 'SEC_CONFIG = $(Dynamic) ; # Config files that are changed infrequently' echo 'SEC_TTY = $(Dynamic)-ugp ; # Tty files change ownership at login' echo 'SEC_LOG = $(Growing) ; # Files that grow, should never change ownership' echo 'SEC_INVARIANT = +tpug ; # Directories that should never change permission or ownership' echo 'SIG_LOW = 33 ; # Non-critical files of minimal security impact' echo 'SIG_MED = 66 ; # Non-critical files of significant security impact' echo 'SIG_HI = 100 ; # Critical files - significant points of vulnerability' echo echo '# Commonly accessed directories that should remain static with regards to owner and group' echo '(' echo ' rulename = "Invariant Directories",' echo ' severity = $(SIG_MED)' echo ')' echo '{' echo ' / -> $(SEC_INVARIANT) (recurse = 0) ;' echo ' /home -> $(SEC_INVARIANT) (recurse = 0) ;' echo ' /etc -> $(SEC_INVARIANT) (recurse = 0) ;' echo '}' echo echo '(' echo ' rulename = "Temporary directories",' echo ' recurse = false,' echo ' severity = $(SIG_LOW)' echo ')' echo '{' echo ' /usr/tmp -> $(SEC_INVARIANT) ; # link to /var/tmp' echo ' /var/tmp -> $(SEC_INVARIANT) ;' echo ' /tmp -> $(SEC_INVARIANT) ;' echo '}' echo echo '# Tripwire Data Files - Configuration Files, Policy Files, Keys, Reports, Databases' echo '(' echo ' rulename = "Tripwire Data Files",' echo ' severity = $(SIG_HI)' echo ')' echo '{' echo ' # NOTE: inode attribute removed on policy and config files.' echo ' # When Tripwire creates a backup, it does so by renaming the old' echo ' # file and creating a new one (which will have a new inode number).' echo ' # Inode is left turned on for encryption key files.' echo echo ' # NOTE: Integrity checks will trigger this rule until a database' echo ' # update is run, because the database file does not exist before that point.' echo echo ' $(TWDB) -> $(SEC_CONFIG) -i ;' echo ' $(TWPOL)/tw.pol -> $(SEC_BIN) -i ;' echo ' $(TWPOL)/tw.cfg -> $(SEC_BIN) -i ;' echo ' $(TWLKEY)/$(HOSTNAME)-local.key -> $(SEC_BIN) ;' echo ' $(TWSKEY)/site.key -> $(SEC_BIN) ;' echo echo ' # Do not scan the individual reports' echo ' $(TWREPORT) -> $(SEC_CONFIG) (recurse=0) ;' echo '}' } make_footer () { echo echo ' # Legacy references from RedHat config file' echo echo ' ##################################################' echo ' # These files change every time the system boots #' echo ' ##################################################' echo '(' echo ' rulename = "System Boot Changes",' echo ' severity = $(SIG_HI)' echo ')' echo '{' echo ' # /var/lock/subsys -> $(SEC_CONFIG) ; # superfluous in gentoo?' echo ' /var/run -> $(SEC_CONFIG) ; # would -i tolerate modification, e.g., restart?' echo ' # /var/log -> $(SEC_LOG) ; # does not tolerate log rotation' echo ' /etc/ioctl.save -> $(SEC_CONFIG) ; # likely superfluous: see sysvinit' echo ' /etc/mtab -> $(SEC_CONFIG) -i ; # Inode number changes on any mount' echo ' /etc/.pwd.lock -> $(SEC_CONFIG) ; # Useless file, but shows password activity' echo '}' echo echo '(' echo ' rulename = "Security Control File",' echo ' severity = $(SIG_HI)' echo ')' echo '{' echo ' /etc/security -> $(SEC_CRIT) ;' echo '}' echo echo '#=============================================================================' echo '#' echo '# Copyright 2000 Tripwire, Inc.' echo '# Tripwire is a registered trademark of Tripwire,Inc.' echo '# (in the United States and other countries)' echo '# All rights reserved.' echo '#' echo '# Linux is a registered trademark of Linus Torvalds.' echo '#' echo '#=============================================================================' echo '#' echo '# Permission is granted to make and distribute verbatim copies of this document' echo '# provided the copyright notice and this permission notice are preserved on all' echo '# copies.' echo '#' echo '# Permission is granted to copy and distribute modified versions of this' echo '# document under the conditions for verbatim copying, provided that the entire' echo '# resulting derived work is distributed under the terms of a permission notice' echo '# identical to this one.' echo '#' echo '######### END of tripwire Policy Text File #########' } # ------- Cycle through RULENAME/PACKAGES assignments # "make_package_rules" routine Cycle through the numbered RULENAME/PACKAGES assignments make_package_rules () { count=${#RULENAME[@]} [ "$DEBUGME" == "y" ] && count=2 for (( i = 0 ; i < count ; i++ )) do list_files done } # "list_files" routine is an "Outer" output loop # It makes the header for the tripewire rule, including optional "emailto" field # It forwards package and file names to other routines. # # Uses equery to find whether or not a package is installed # Names of installed packages are passed to "inner" output loop list_files () { echo echo "################################################################" echo "# RuleName: ${RULENAME[$i]}" [ -n "${PACKAGES[$i]}" ] && echo "# Packages: ${PACKAGES[$i]}" [ -n "${FILELIST[$i]}" ] && echo "# FileNames: ${FILELIST[$i]}" [ -n "${XWINLIST[$i]}" ] && echo "# XwinNames: ${XWINLIST[$i]}" [ -n "${SKIPINOD[$i]}" ] && echo "# SkipInode: ${SKIPINOD[$i]}" echo "################################################################" echo \( echo " rulename = \"${RULENAME[$i]}\"," echo -n " severity = \$(${SEVERITY[$i]:-SIG_HI})" [ -n "${EMAILTO[$i]}" ] && echo -e ",\\n emailto = ${EMAILTO[$i]}" || echo echo \) echo \{ [ -n "${IGNORELIST[$i]}" ] && echo "# ${RULENAME[$i]}: Ignore changes to these files" for targetfile in ${IGNORELIST[$i]} do [ -e "$targetfile" ] && echo " !$targetfile ;" done [ -n "${IGNORELIST[$i]}" ] && echo for package in ${PACKAGES[$i]} do equery -q files $package > $TMP_FILE [ -s "$TMP_FILE" ] && extract_package_filenames done # Block listing of directory entries from the /proc/* wildcard [ -n "${FILELIST[$i]}" ] && echo -e "\\n# ${RULENAME[$i]}: ${REMARKS[$i]}" for targetfile in ${FILELIST[$i]} do if [ -d "$targetfile" -a -n "`expr $targetfile : '\(/proc/\)'`" ]; then true elif [ -d "$targetfile" -a -n "`expr $targetfile : '\(/lost+found\)'`" ]; then true elif [ -e $targetfile ]; then output_line select_policy fi done [ -n "${XWINLIST[$i]}" ] && echo -e "\\n# ${RULENAME[$i]}: ${REMARKS[$i]}" for targetfile in ${XWINLIST[$i]} do if [ -e "$targetfile" ]; then output_line select_policy fi done [ -n "${SKIPINOD[$i]}" ] && echo -e "\\n# ${RULENAME[$i]}: ${REMARKS[$i]}" for targetfile in ${SKIPINOD[$i]} do [ -e "$targetfile" ] && { output_line echo "-> \$(${ETCSECVALUE[$i]:-SEC_CONFIG}) -i ; # Changes Inode number" } done echo \} } # "extract_package_filenames" routine is an "Inner" output loop - used for packages only # `equery` was used previously to obtain a list of all files installed by the package # # Only filenames with "bin/", "/etc/", or "/var/log/" are passed from package lists # Adding "/lib/.*[.]s[ho]" adds substantial bulk # Directory names and zero-size files are excluded from package output extract_package_filenames () { echo echo "# ${RULENAME[$i]}: $package" echo for targetfile in `grep -e /etc/ -e bin/ -e /var/log/ $TMP_FILE` do [ ! -d $targetfile -a -s $targetfile ] && { output_line select_policy } done } # "output_line" routine adds a variable number of tabs to obtain alignment # The width of the targetfile name is increased by 2 to account for indent # The maximum number of additional tabs is the digit after "10#" # The width of the TAB is taken as 8 characters output_line () { MAKE_TABS=$[(10#4-(${#targetfile}+2)/8)] echo -n " $targetfile" echo -e -n \\t # At least one TAB for (( z = 0 ; z < MAKE_TABS ; z++ )) # Up to five TABs do echo -e -n \\t done } # "select_policy" routine runs each filename through a gauntlet, picking up # a $Filetype handle depending on which attribute it matches last. select_policy () { Filetype=Config [ -n "`expr $targetfile : '\(/etc/\)'`" ] && Filetype=Config [ -n "`expr $targetfile : '\(/lib/\)'`" ] && Filetype=Lib [ -n "`expr $targetfile : '\(/var/log\)'`" ] && Filetype=Log [ -n "`expr $targetfile : '\(/root/\)'`" ] && Filetype=RootFile [ -n "`expr $targetfile : '\(/lib/modules\)'`" ] && Filetype=Kernel [ -n "`file -b $targetfile | grep kernel`" ] && Filetype=Kernel [ -b $targetfile ] && Filetype=Block [ -c $targetfile ] && Filetype=Char [ -n "`expr $targetfile : '\(/dev/tty\)'`" ] && Filetype=Tty [ -x $targetfile ] && Filetype=Bin [ -d $targetfile ] && Filetype=Dir [ $targetfile == "/root" ] && Filetype=RootDir [ -u $targetfile ] && Filetype=SUID case $Filetype in SUID ) echo "-> \$(SEC_SUID) ;" ;; RootDir ) echo "-> \$(SEC_CRIT) ; # Catch all additions to /root" ;; RootFile ) echo "-> \$(${ETCSECVALUE[$i]:-SEC_CONFIG}) ;" ;; Dir ) echo "-> \$(${ETCSECVALUE[$i]:-SEC_CONFIG}) ${RECURSE[$i]};" ;; Bin ) echo "-> \$(${BINSECVALUE[$i]:-SEC_CRIT}) ;" ;; Kernel ) echo "-> \$(${BINSECVALUE[$i]:-SEC_CRIT}) ;" ;; Tty ) echo "-> \$(${BINSECVALUE[$i]:-SEC_TTY}) ;" ;; Log ) echo "-> \$(${LOGSECVALUE[$i]:-SEC_LOG}) ;" ;; Lib ) echo "-> \$(${BINSECVALUE[$i]:-SEC_CRIT}) ;" ;; Config ) echo "-> \$(${ETCSECVALUE[$i]:-SEC_CONFIG}) ;" ;; Char ) echo "-> \$(Device) ;" ;; Block ) echo "-> \$(Device) ;" ;; esac } # =================================================================== # Workings of the policy generator itself, not workings of the policy # =================================================================== equery_error_exit () { echo echo This script depends on equery to obtain meaningful output. echo On gentoo, \`emerge gentoolkit\` exit 1 } tripwire_error_exit () { echo echo "This script has no known function aside from tripwire." >&2 echo "On gentoo, \`emerge tripwire\`" >&2 echo "Continuing even though tripwire is not found on this system ..." >&2 echo [ "$DEBUGME" == "y" ] || sleep 5 } ################################################################# # Main Routine # ################################################################# make_policy_text_file () { for i in equery tripwire; do hash $i || ${i}_error_exit done make_header make_package_rules make_footer } if [ -n "$1" ]; then { TRIPWIRE_CFG=/etc/tripwire/twpol-`date +%s`.txt if [ ! -d /etc/tripwire ]; then echo Creation of twpol.txt file depends on existence of the directory /etc/tripwire echo Running `basename $0` with no parameters generates text policy to STDOUT echo Exiting. exit 1 else echo echo Showing generation of $TRIPWIRE_CFG echo echo After policy file is generated, you will have an opportunity echo to invoke tripwire to update the encrypted policy and database echo echo Sleeping 10 seconds ... [ "$DEBUGME" == "y" ] || sleep 10 fi make_policy_text_file | tee $TRIPWIRE_CFG echo echo Completed generation of $TRIPWIRE_CFG echo echo To update encrypted policy file /etc/tripwire/tw.pol, run echo tripwire -m p -Z low $TRIPWIRE_CFG echo echo Then acknowledge/accept resulting change to /etc/tripwire/tw.pol file, run echo tripwire -m c -I echo echo -n "Take those steps now? [y/N]: " read RUN_TRIPWIRE if [ "${RUN_TRIPWIRE,Y}" == "y" ]; then tripwire -m p -Z low $TRIPWIRE_CFG echo echo Policy and Database files updated by \`tripwire -m p\` command echo Starting interactive integrity check using \`tripwire -m c -I\` echo tripwire -m c -I else echo Skipping tripwire operations. Goodbye. fi } else echo "Run `basename $0` with any parameter(s) to automate installing updated policy." >&2 echo "Sleeping 5 seconds ..." >&2 echo [ "$DEBUGME" == "y" ] || sleep 5 make_policy_text_file fi ################################################################# ################################################################# # Nothing But Junk Below # Routine Might be Used to Create List of Package Names ################################################################# SYSTEM_FILE_LIST=/root/system-files.txt list_system_files () { for i in `EMERGE_DEFAULT_OPTS="" emerge -peq system | cut -d"]" -f2`; do echo $i # equery files $i done } #echo Making list of system files ... #list_system_files > $SYSTEM_FILE_LIST